diff --git a/src/metabase/models/interface.clj b/src/metabase/models/interface.clj
index d8ebb1d23836f17fff6c8b34768c3b90a4be264c..45ed8e4ec11393e3c7bf40cd4232cf352e0bc7c4 100644
--- a/src/metabase/models/interface.clj
+++ b/src/metabase/models/interface.clj
@@ -68,6 +68,10 @@
   :in  encrypted-json-in
   :out (comp cached-encrypted-json-out u/jdbc-clob->str))
 
+(models/add-type! :encrypted-text
+  :in  encryption/maybe-encrypt
+  :out (comp encryption/maybe-decrypt u/jdbc-clob->str))
+
 (defn compress
   "Compress OBJ, returning a byte array."
   [obj]
diff --git a/src/metabase/models/setting.clj b/src/metabase/models/setting.clj
index fd80041abc20e55e337e9604edb7993e25d9db8b..8c6029af06b7f52b934ed169da7a23cf64b58b2f 100644
--- a/src/metabase/models/setting.clj
+++ b/src/metabase/models/setting.clj
@@ -49,7 +49,7 @@
 (u/strict-extend (class Setting)
   models/IModel
   (merge models/IModelDefaults
-         {:types (constantly {:value :clob})}))
+         {:types (constantly {:value :encrypted-text})}))
 
 
 (def ^:private Type
@@ -192,8 +192,13 @@
 ;;; +----------------------------------------------------------------------------------------------------------------+
 
 (defn- update-setting! [setting-name new-value]
-  (db/update-where! Setting {:key setting-name}
-    :value new-value))
+  ;; This is indeed a very annoying way of having to do things, but `update-where!` doesn't call `pre-update` (in case
+  ;; it updates thousands of objects). So we need to manually trigger `pre-update` behavior by calling `do-pre-update`
+  ;; so that `value` can get encrypted if `MB_ENCRYPTION_SECRET_KEY` is in use. Then take that possibly-encrypted
+  ;; value and pass that into `update-where!`.
+  (let [{maybe-encrypted-new-value :value} (models/do-pre-update Setting {:value new-value})]
+    (db/update-where! Setting {:key setting-name}
+      :value maybe-encrypted-new-value)))
 
 (defn- set-new-setting!
   "Insert a new row for a Setting with SETTING-NAME and SETTING-VALUE.
diff --git a/src/metabase/util.clj b/src/metabase/util.clj
index 9d39e7ad08da90faf39d42a830250f236a66f4fd..dca42ebe128c2bcb31233c135a71ea401c10647b 100644
--- a/src/metabase/util.clj
+++ b/src/metabase/util.clj
@@ -515,7 +515,7 @@
                   (select-nested-keys v nested-keys))})))
 
 (defn base64-string?
-  "Is S a Base-64 encoded string?"
+  "Is `s` a Base-64 encoded string?"
   ^Boolean [s]
   (boolean (when (string? s)
              (re-find #"^[0-9A-Za-z/+]+=*$" s))))
diff --git a/src/metabase/util/encryption.clj b/src/metabase/util/encryption.clj
index fd920c98e479c8e84c9a472acf04d4d3cc8d0d9b..bcd2624ad6dfd2930e7ca4d41573945867ca68a9 100644
--- a/src/metabase/util/encryption.clj
+++ b/src/metabase/util/encryption.clj
@@ -1,5 +1,6 @@
 (ns metabase.util.encryption
-  "Utility functions for encrypting and decrypting strings using AES256 CBC + HMAC SHA512 and the `MB_ENCRYPTION_SECRET_KEY` env var."
+  "Utility functions for encrypting and decrypting strings using AES256 CBC + HMAC SHA512 and the
+  `MB_ENCRYPTION_SECRET_KEY` env var."
   (:require [buddy.core
              [codecs :as codecs]
              [crypto :as crypto]
@@ -8,54 +9,62 @@
             [clojure.tools.logging :as log]
             [environ.core :as env]
             [metabase.util :as u]
+            [puppetlabs.i18n.core :refer [trs]]
             [ring.util.codec :as codec]))
 
 (defn secret-key->hash
-  "Generate a 64-byte byte array hash of SECRET-KEY using 100,000 iterations of PBKDF2+SHA512."
+  "Generate a 64-byte byte array hash of `secret-key` using 100,000 iterations of PBKDF2+SHA512."
   ^bytes [^String secret-key]
   (kdf/get-bytes (kdf/engine {:alg        :pbkdf2+sha512
                               :key        secret-key
                               :iterations 100000}) ; 100,000 iterations takes about ~160ms on my laptop
                  64))
 
-;; apperently if you're not tagging in an arglist, `^bytes` will set the `:tag` metadata to `clojure.core/bytes` (ick) so you have to do `^{:tag 'bytes}` instead
+;; apperently if you're not tagging in an arglist, `^bytes` will set the `:tag` metadata to `clojure.core/bytes` (ick)
+;; so you have to do `^{:tag 'bytes}` instead
 (defonce ^:private ^{:tag 'bytes} default-secret-key
   (when-let [secret-key (env/env :mb-encryption-secret-key)]
     (when (seq secret-key)
       (assert (>= (count secret-key) 16)
-        "MB_ENCRYPTION_SECRET_KEY must be at least 16 characters.")
+        (trs "MB_ENCRYPTION_SECRET_KEY must be at least 16 characters."))
       (secret-key->hash secret-key))))
 
 ;; log a nice message letting people know whether DB details encryption is enabled
 (log/info
- (format "DB details encryption is %s for this Metabase instance. %s"
-         (if default-secret-key "ENABLED" "DISABLED")
-         (u/emoji (if default-secret-key "🔐" "🔓")))
- "\nSee"
- "http://www.metabase.com/docs/latest/operations-guide/start.html#encrypting-your-database-connection-details-at-rest"
- "for more information.")
+ (if default-secret-key
+   (trs "Saved credentials encryption is ENABLED for this Metabase instance.")
+   (trs "Saved credentials encryption is DISABLED for this Metabase instance."))
+ (u/emoji (if default-secret-key "🔐" "🔓"))
+ (trs "\nFor more information, see")
+ "https://www.metabase.com/docs/latest/operations-guide/start.html#encrypting-your-database-connection-details-at-rest")
 
 (defn encrypt
-  "Encrypt string S as hex bytes using a SECRET-KEY (a 64-byte byte array), by default the hashed value of `MB_ENCRYPTION_SECRET_KEY`."
+  "Encrypt string `s` as hex bytes using a `secret-key` (a 64-byte byte array), by default the hashed value of
+  `MB_ENCRYPTION_SECRET_KEY`."
   (^String [^String s]
    (encrypt default-secret-key s))
   (^String [^String secret-key, ^String s]
    (let [initialization-vector (nonce/random-bytes 16)]
-     (codec/base64-encode (byte-array (concat initialization-vector
-                                              (crypto/encrypt (codecs/to-bytes s) secret-key initialization-vector {:algorithm :aes256-cbc-hmac-sha512})))))))
+     (codec/base64-encode
+      (byte-array
+       (concat initialization-vector
+               (crypto/encrypt (codecs/to-bytes s) secret-key initialization-vector
+                               {:algorithm :aes256-cbc-hmac-sha512})))))))
 
 (defn decrypt
-  "Decrypt string S  using a SECRET-KEY (a 64-byte byte array), by default the hashed value of `MB_ENCRYPTION_SECRET_KEY`."
+  "Decrypt string `s` using a `secret-key` (a 64-byte byte array), by default the hashed value of
+  `MB_ENCRYPTION_SECRET_KEY`."
   (^String [^String s]
    (decrypt default-secret-key s))
   (^String [secret-key, ^String s]
    (let [bytes                           (codec/base64-decode s)
          [initialization-vector message] (split-at 16 bytes)]
-     (codecs/bytes->str (crypto/decrypt (byte-array message) secret-key (byte-array initialization-vector) {:algorithm :aes256-cbc-hmac-sha512})))))
+     (codecs/bytes->str (crypto/decrypt (byte-array message) secret-key (byte-array initialization-vector)
+                                        {:algorithm :aes256-cbc-hmac-sha512})))))
 
 
 (defn maybe-encrypt
-  "If `MB_ENCRYPTION_SECRET_KEY` is set, return an encrypted version of S; otherwise return S as-is."
+  "If `MB_ENCRYPTION_SECRET_KEY` is set, return an encrypted version of `s`; otherwise return `s` as-is."
   (^String [^String s]
    (maybe-encrypt default-secret-key s))
   (^String [secret-key, ^String s]
@@ -65,7 +74,7 @@
      s)))
 
 (defn maybe-decrypt
-  "If `MB_ENCRYPTION_SECRET_KEY` is set and S is encrypted, decrypt S; otherwise return S as-is."
+  "If `MB_ENCRYPTION_SECRET_KEY` is set and `s` is encrypted, decrypt `s`; otherwise return `s` as-is."
   (^String [^String s]
    (maybe-decrypt default-secret-key s))
   (^String [secret-key, ^String s]
@@ -75,7 +84,10 @@
        (catch Throwable e
          (if (u/base64-string? s)
            ;; if we can't decrypt `s`, but it *is* encrypted, log an error message and return `nil`
-           (log/error "Cannot decrypt encrypted details. Have you changed or forgot to set MB_ENCRYPTION_SECRET_KEY?" (.getMessage e))
+           (log/error
+            (trs "Cannot decrypt encrypted credentials. Have you changed or forgot to set MB_ENCRYPTION_SECRET_KEY?")
+            (.getMessage e)
+            (u/filtered-stacktrace e))
            ;; otherwise return S without decrypting. It's probably not decrypted in the first place
            s)))
      s)))
diff --git a/test/metabase/models/setting_test.clj b/test/metabase/models/setting_test.clj
index cf617ab39ec60da3fc1759968595fdd9613a7108..b4a76c5eb2b5a7e05be85d31a77c8153cb8ef4de 100644
--- a/test/metabase/models/setting_test.clj
+++ b/test/metabase/models/setting_test.clj
@@ -2,6 +2,10 @@
   (:require [expectations :refer :all]
             [metabase.models.setting :as setting :refer [defsetting Setting]]
             [metabase.test.util :refer :all]
+            [metabase.util :as u]
+            [metabase.util
+             [encryption :as encryption]
+             [encryption-test :as encryption-test]]
             [puppetlabs.i18n.core :refer [tru]]
             [toucan.db :as db]))
 
@@ -167,7 +171,12 @@
 
 ;; all
 (expect
-  {:key :test-setting-2, :value "TOUCANS", :description "Test setting - this only shows up in dev (2)",  :is_env_setting false, :env_name "MB_TEST_SETTING_2", :default "[Default Value]"}
+  {:key            :test-setting-2
+   :value          "TOUCANS"
+   :description    "Test setting - this only shows up in dev (2)"
+   :is_env_setting false
+   :env_name       "MB_TEST_SETTING_2"
+   :default        "[Default Value]"}
   (do (set-settings! nil "TOUCANS")
       (some (fn [setting]
               (when (re-find #"^test-setting-2$" (name (:key setting)))
@@ -176,8 +185,18 @@
 
 ;; all
 (expect
-  [{:key :test-setting-1, :value nil, :is_env_setting true, :env_name "MB_TEST_SETTING_1", :description "Test setting - this only shows up in dev (1)", :default "Using $MB_TEST_SETTING_1"}
-   {:key :test-setting-2, :value "S2", :is_env_setting false, :env_name "MB_TEST_SETTING_2",  :description "Test setting - this only shows up in dev (2)", :default "[Default Value]"}]
+  [{:key            :test-setting-1
+    :value          nil
+    :is_env_setting true
+    :env_name       "MB_TEST_SETTING_1"
+    :description    "Test setting - this only shows up in dev (1)"
+    :default        "Using $MB_TEST_SETTING_1"}
+   {:key            :test-setting-2
+    :value          "S2"
+    :is_env_setting false,
+    :env_name       "MB_TEST_SETTING_2"
+    :description    "Test setting - this only shows up in dev (2)"
+    :default        "[Default Value]"}]
   (do (set-settings! nil "S2")
       (for [setting (setting/all)
             :when   (re-find #"^test-setting-\d$" (name (:key setting)))]
@@ -269,3 +288,32 @@
     (toucan-name "Banana Beak")
     ;; ok, make sure the setting was set
     (toucan-name)))
+
+
+;;; ----------------------------------------------- Encrypted Settings -----------------------------------------------
+
+(defn- actual-value-in-db [setting-key]
+  (-> (db/query {:select [:value]
+                 :from   [:setting]
+                 :where  [:= :key (name setting-key)]})
+      first :value u/jdbc-clob->str))
+
+;; If encryption is *enabled*, make sure Settings get saved as encrypted!
+(expect
+  (encryption-test/with-secret-key "ABCDEFGH12345678"
+    (toucan-name "Sad Can")
+    (u/base64-string? (actual-value-in-db :toucan-name))))
+
+;; make sure it can be decrypted as well...
+(expect
+  "Sad Can"
+  (encryption-test/with-secret-key "12345678ABCDEFGH"
+    (toucan-name "Sad Can")
+    (encryption/decrypt (actual-value-in-db :toucan-name))))
+
+;; But if encryption is not enabled, of course Settings shouldn't get saved as encrypted.
+(expect
+  "Sad Can"
+  (encryption-test/with-secret-key nil
+    (toucan-name "Sad Can")
+    (actual-value-in-db :toucan-name)))
diff --git a/test/metabase/util/encryption_test.clj b/test/metabase/util/encryption_test.clj
index a858a6b1243f5060b8291ecc9ac9000e685d2155..026a6388ff4f6d8397b7652ea098ab706eddb507 100644
--- a/test/metabase/util/encryption_test.clj
+++ b/test/metabase/util/encryption_test.clj
@@ -5,6 +5,18 @@
             [metabase.test.util :as tu]
             [metabase.util.encryption :as encryption]))
 
+(defn do-with-secret-key [^String secret-key, f]
+  (with-redefs [encryption/default-secret-key (when (seq secret-key)
+                                                (encryption/secret-key->hash secret-key))]
+    (f)))
+
+(defmacro with-secret-key
+  "Run `body` with the encryption secret key temporarily bound to `secret-key`. Useful for testing how functions behave
+  with and without encryption disabled."
+  {:style/indent 1}
+  [^String secret-key, & body]
+  `(do-with-secret-key ~secret-key (fn [] ~@body)))
+
 (def ^:private secret   (encryption/secret-key->hash "Orw0AAyzkO/kPTLJRxiyKoBHXa/d6ZcO+p+gpZO/wSQ="))
 (def ^:private secret-2 (encryption/secret-key->hash "0B9cD6++AME+A7/oR7Y2xvPRHX3cHA2z7w+LbObd/9Y="))
 
@@ -49,7 +61,7 @@
 
 (expect
   (some (fn [[_ _ message]]
-          (str/includes? message (str "Cannot decrypt encrypted details. Have you changed or forgot to set "
+          (str/includes? message (str "Cannot decrypt encrypted credentials. Have you changed or forgot to set "
                                       "MB_ENCRYPTION_SECRET_KEY? Message seems corrupt or manipulated.")))
         (tu/with-log-messages
           (encryption/maybe-decrypt secret-2 (encryption/encrypt secret "WOW")))))