diff --git a/src/metabase/query_processor/middleware/cache.clj b/src/metabase/query_processor/middleware/cache.clj
index 3923418bfbf97c12b1681d4281a1b7c441461e99..30b2a63cd138f1410b4f0e83128a8bf0781bd5f1 100644
--- a/src/metabase/query_processor/middleware/cache.clj
+++ b/src/metabase/query_processor/middleware/cache.clj
@@ -18,9 +18,12 @@
              [config :as config]
              [public-settings :as public-settings]
              [util :as u]]
+            [metabase.plugins.classloader :as classloader]
             [metabase.query-processor.middleware.cache-backend.interface :as i]
             [metabase.query-processor.util :as qputil]
-            [metabase.util.date :as du]))
+            [metabase.util
+             [date :as du]
+             [i18n :refer [trs]]]))
 
 ;; TODO - Why not make this an option in the query itself? :confused:
 (def ^:dynamic ^Boolean *ignore-cached-results*
@@ -31,13 +34,10 @@
 
 ;;; ---------------------------------------------------- Backend -----------------------------------------------------
 
-(def ^:private backend-instance
-  (atom nil))
-
 (defn- valid-backend? [instance] (extends? i/IQueryProcessorCacheBackend (class instance)))
 
 (defn- get-backend-instance-in-namespace
-  "Return a valid query cache backend `instance` in BACKEND-NS-SYMB, or throw an Exception if none exists."
+  "Return a valid query cache backend instance in `backend-ns-symb`, or throw an Exception if none exists."
   ;; if for some reason the resolved var doesn't satisfy `IQueryProcessorCacheBackend` we'll reload the namespace
   ;; it belongs to and try one more time.
   ;; This fixes the issue in dev sessions where the interface namespace gets reloaded causing the cache implementation
@@ -54,19 +54,23 @@
        :else                  (throw (Exception. (format "%s/instance doesn't satisfy IQueryProcessorCacheBackend"
                                                          backend-ns-symb)))))))
 
-(defn- set-backend!
-  "Set the cache backend to the cache defined by the keyword BACKEND.
+(defn- resolve-backend
+  "Get the cache backend to the cache defined by the keyword `backend`.
 
    (This should be something like `:db`, `:redis`, or `:memcached`. See the
    documentation in `metabase.query-processor.middleware.cache-backend.interface` for details on how this works.)"
   ([]
-   (set-backend! (config/config-kw :mb-qp-cache-backend)))
+   (resolve-backend (config/config-kw :mb-qp-cache-backend)))
+
   ([backend]
+   (classloader/the-classloader)
    (let [backend-ns-symb (symbol (str "metabase.query-processor.middleware.cache-backend." (munge (name backend))))]
      (require backend-ns-symb)
-     (log/info "Using query processor cache backend:" (u/format-color 'blue backend) (u/emoji "💾"))
-     (reset! backend-instance (get-backend-instance-in-namespace backend-ns-symb)))))
+     (log/info (trs "Using query processor cache backend: {0}" (u/format-color 'blue backend)) (u/emoji "💾"))
+     (get-backend-instance-in-namespace backend-ns-symb))))
 
+(defonce ^:private backend-instance
+  (delay (resolve-backend)))
 
 
 ;;; ------------------------------------------------ Cache Operations ------------------------------------------------
@@ -130,7 +134,4 @@
       ;; wait until we're actually going to use the cache before initializing the backend. We don't want to initialize
       ;; it when the files get compiled, because that would give it the wrong version of the
       ;; `IQueryProcessorCacheBackend` protocol
-      (do
-        (when-not @backend-instance
-          (set-backend!))
-        (run-query-with-cache qp query respond raise canceled-chan)))))
+      (run-query-with-cache qp query respond raise canceled-chan))))