diff --git a/frontend/src/metabase/services.js b/frontend/src/metabase/services.js
index bdc959dc8cd8e72536802509bb3473136e47a435..c380838cea2e3b6f9cfb4a3ca581c97f2252810a 100644
--- a/frontend/src/metabase/services.js
+++ b/frontend/src/metabase/services.js
@@ -212,7 +212,7 @@ export const LdapApi = {
 };
 
 export const MetabaseApi = {
-  db_list: GET("/api/database"),
+  db_list: GET("/api/database", res => res["data"]),
   db_create: POST("/api/database"),
   db_validate: POST("/api/database/validate"),
   db_add_sample_dataset: POST("/api/database/sample_dataset"),
diff --git a/src/metabase/api/database.clj b/src/metabase/api/database.clj
index d562b5ae586b8dabae47471b5c257f24636d1796..9a548840b05d14dca6561355b21be68520ba503f 100644
--- a/src/metabase/api/database.clj
+++ b/src/metabase/api/database.clj
@@ -22,6 +22,7 @@
             [metabase.models.table :refer [Table]]
             [metabase.public-settings :as public-settings]
             [metabase.sample-data :as sample-data]
+            [metabase.server.middleware.offset-paging :as offset-paging]
             [metabase.sync.analyze :as analyze]
             [metabase.sync.field-values :as sync-field-values]
             [metabase.sync.schedules :as sync.schedules]
@@ -165,8 +166,15 @@
     (cond-> dbs
       (and (source-query-cards-exist?) virtual-db-metadata) (concat [virtual-db-metadata]))))
 
-(defn- dbs-list [& {:keys [include-tables? include-saved-questions-db? include-saved-questions-tables?]}]
-  (when-let [dbs (seq (filter mi/can-read? (db/select Database {:order-by [:%lower.name :%lower.engine]})))]
+(defn- dbs-list [& {:keys [include-tables?
+                           include-saved-questions-db?
+                           include-saved-questions-tables?
+                           limit
+                           offset]}]
+  (when-let [dbs (seq (filter mi/can-read? (db/select Database
+                                                      {:order-by [:%lower.name :%lower.engine]
+                                                       :limit limit
+                                                       :offset offset})))]
     (cond-> (add-native-perms-info dbs)
       include-tables?             add-tables
       include-saved-questions-db? (add-saved-questions-virtual-database :include-tables? include-saved-questions-tables?))))
@@ -210,10 +218,15 @@
                                           (if (seq include_cards)
                                             true
                                             include-tables?))]
-    (or (dbs-list :include-tables?                  include-tables?
-                  :include-saved-questions-db?      include-saved-questions-db?
-                  :include-saved-questions-tables?  include-saved-questions-tables?)
-        [])))
+    {:data  (or (dbs-list :include-tables?                  include-tables?
+                          :include-saved-questions-db?      include-saved-questions-db?
+                          :include-saved-questions-tables?  include-saved-questions-tables?
+                          :limit                            offset-paging/*limit*
+                          :offset                           offset-paging/*offset*)
+                [])
+     :limit  offset-paging/*limit*
+     :offset offset-paging/*offset*
+     :total  (db/count Database)}))
 
 
 ;;; --------------------------------------------- GET /api/database/:id ----------------------------------------------
diff --git a/test/metabase/api/database_test.clj b/test/metabase/api/database_test.clj
index 3d4ee13ee49938c4f5053624ff8b371ceeb52523..3147b5e028b3a5fb5ceb99e04d6fc686d4e964fb 100644
--- a/test/metabase/api/database_test.clj
+++ b/test/metabase/api/database_test.clj
@@ -357,17 +357,27 @@
       (testing "Database details *should not* come back for Rasta since she's not a superuser"
         (let [expected-keys (-> (into #{:features :native_permissions} (keys (Database (mt/id))))
                                 (disj :details))]
-          (doseq [db ((mt/user->client :rasta) :get 200 "database")]
+          (doseq [db (:data ((mt/user->client :rasta) :get 200 "database"))]
             (testing (format "Database %s %d %s" (:engine db) (u/the-id db) (pr-str (:name db)))
               (is (= expected-keys
                      (set (keys db)))))))))
 
+    (doseq [query-param ["?limit=2"
+                         "?limit=2&offset=1"]]
+      (testing query-param
+        (mt/with-temp*
+          [Database [{db-id :id1, db-name :name1} {:engine (u/qualified-name ::test-driver)}]
+           Database [{db-id :id2, db-name :name2} {:engine (u/qualified-name ::test-driver)}]]
+
+          (let [db (:data ((mt/user->client :rasta) :get 200 (str "database" query-param)))]
+            (is (= 2 (count db)))))))
+
     ;; ?include=tables and ?include_tables=true mean the same thing so test them both the same way
     (doseq [query-param ["?include_tables=true"
                          "?include=tables"]]
       (testing query-param
         (mt/with-temp Database [{db-id :id, db-name :name} {:engine (u/qualified-name ::test-driver)}]
-          (doseq [db ((mt/user->client :rasta) :get 200 (str "database" query-param))]
+          (doseq [db (:data ((mt/user->client :rasta) :get 200 (str "database" query-param)))]
             (testing (format "Database %s %d %s" (:engine db) (u/the-id db) (pr-str (:name db)))
               (is (= (expected-tables db)
                      (:tables db))))))))))
@@ -381,7 +391,7 @@
                 :id                 mbql.s/saved-questions-virtual-database-id
                 :features           ["basic-aggregations"]
                 :is_saved_questions true}
-               (last ((mt/user->client :lucky) :get 200 "database?saved=true"))))))
+               (last (:data ((mt/user->client :lucky) :get 200 "database?saved=true")))))))
 
     (testing "We should not include the saved questions virtual DB if there aren't any cards"
       (not-any?
@@ -389,7 +399,7 @@
        ((mt/user->client :lucky) :get 200 "database?saved=true")))
     (testing "Omit virtual DB if nested queries are disabled"
       (tu/with-temporary-setting-values [enable-nested-queries false]
-        (every? some? ((mt/user->client :lucky) :get 200 "database?saved=true"))))))
+        (every? some? (:data ((mt/user->client :lucky) :get 200 "database?saved=true")))))))
 
 (deftest fetch-databases-with-invalid-driver-test
   (testing "GET /api/database"
@@ -400,7 +410,7 @@
                           "?saved=true"
                           "?include=tables"]]
             (testing (format "\nparams = %s" (pr-str params))
-              (let [db-ids (set (map :id ((mt/user->client :lucky) :get 200 (str "database" params))))]
+              (let [db-ids (set (map :id (:data ((mt/user->client :lucky) :get 200 (str "database" params)))))]
                 (testing "DB should still come back, even though driver is invalid :shrug:"
                   (is (contains? db-ids db-id)))))))))))
 
@@ -436,14 +446,14 @@
       (letfn [(fetch-virtual-database []
                 (some #(when (= (:name %) "Saved Questions")
                          %)
-                      ((mt/user->client :crowberto) :get 200 (str "database" params))))]
+                      (:data ((mt/user->client :crowberto) :get 200 (str "database" params)))))]
         (testing "Check that we get back 'virtual' tables for Saved Questions"
           (testing "The saved questions virtual DB should be the last DB in the list"
             (mt/with-temp Card [card (card-with-native-query "Kanye West Quote Views Per Month")]
               ;; run the Card which will populate its result_metadata column
               ((mt/user->client :crowberto) :post 202 (format "card/%d/query" (u/the-id card)))
               ;; Now fetch the database list. The 'Saved Questions' DB should be last on the list
-              (let [response (last ((mt/user->client :crowberto) :get 200 (str "database" params)))]
+              (let [response (last (:data ((mt/user->client :crowberto) :get 200 (str "database" params))))]
                 (is (schema= SavedQuestionsDB
                              response))
                 (check-tables-included response (virtual-table-for-card card)))))
@@ -467,7 +477,7 @@
               ((mt/user->client :crowberto) :post 202 (format "card/%d/query" (u/the-id card))))
             ;; Now fetch the database list. The 'Saved Questions' DB should be last on the list. Cards should have their
             ;; Collection name as their Schema
-            (let [response (last ((mt/user->client :crowberto) :get 200 (str "database" params)))]
+            (let [response (last (:data ((mt/user->client :crowberto) :get 200 (str "database" params))))]
               (is (schema= SavedQuestionsDB
                            response))
               (check-tables-included