diff --git a/src/metabase/api/dashboard.clj b/src/metabase/api/dashboard.clj
index d8a4d7ac9744d58a67ed83680320bafdb3bf000c..8610a07408e21db7e623b46715f1c6d55cba9279 100644
--- a/src/metabase/api/dashboard.clj
+++ b/src/metabase/api/dashboard.clj
@@ -283,45 +283,60 @@
              :uncopied discard}
             copy)))
 
+(defn- duplicate-tabs
+  [new-dashboard existing-tabs]
+  (let [new-tab-ids (t2/insert-returning-pks! :model/DashboardTab
+                                              (for [tab existing-tabs]
+                                                (-> tab
+                                                    (assoc :dashboard_id (:id new-dashboard))
+                                                    (dissoc :id :entity_id :created_at :updated_at))))]
+    (zipmap (map :id existing-tabs) new-tab-ids)))
+
 (defn update-cards-for-copy
-  "Update ordered-cards in a dashboard for copying. If shallow copy, returns the cards. If deep copy, replaces ids with
-  id from the newly-copied cards. If there is no new id, it means user lacked curate permissions for the cards
+  "Update ordered-cards in a dashboard for copying.
+  If the dashboard has tabs, fix up the tab ids in ordered-cards to point to the new tabs.
+  Then if shallow copy, return the cards. If deep copy, replace ids with id from the newly-copied cards.
+  If there is no new id, it means user lacked curate permissions for the cards
   collections and it is omitted. Dashboard-id is only needed for useful errors."
-  [dashboard-id ordered-cards deep? id->new-card]
+  [dashboard-id ordered-cards deep? id->new-card id->new-tab-id]
   (when (and deep? (nil? id->new-card))
     (throw (ex-info (tru "No copied card information found")
                     {:user-id api/*current-user-id*
                      :dashboard-id dashboard-id})))
-  (if-not deep?
-    ordered-cards
-    (keep (fn [dashboard-card]
-            (cond
-              ;; text cards need no manipulation
-              (nil? (:card_id dashboard-card))
-              dashboard-card
-
-              ;; if we didn't duplicate, it doesn't go in the dashboard
-              (not (id->new-card (:card_id dashboard-card)))
-              nil
-
-              :else
-              (let [new-id (fn [id]
-                             (-> id id->new-card :id))]
-                (-> dashboard-card
-                    (update :card_id new-id)
-                    (assoc :card (-> dashboard-card :card_id id->new-card))
-                    (m/update-existing :parameter_mappings
-                                       (fn [pms]
-                                         (keep (fn [pm]
-                                                 (m/update-existing pm :card_id new-id))
-                                               pms)))
-                    (m/update-existing :series
-                                       (fn [series]
-                                         (keep (fn [card]
-                                                 (when-let [id' (new-id (:id card))]
-                                                   (assoc card :id id')))
-                                               series)))))))
-          ordered-cards)))
+  (let [ordered-cards (if (seq id->new-tab-id)
+                        (map #(assoc % :dashboard_tab_id (id->new-tab-id (:dashboard_tab_id %)))
+                             ordered-cards)
+                        ordered-cards)]
+    (if-not deep?
+      ordered-cards
+      (keep (fn [dashboard-card]
+              (cond
+                ;; text cards need no manipulation
+                (nil? (:card_id dashboard-card))
+                dashboard-card
+
+                ;; if we didn't duplicate, it doesn't go in the dashboard
+                (not (id->new-card (:card_id dashboard-card)))
+                nil
+
+                :else
+                (let [new-id (fn [id]
+                               (-> id id->new-card :id))]
+                  (-> dashboard-card
+                      (update :card_id new-id)
+                      (assoc :card (-> dashboard-card :card_id id->new-card))
+                      (m/update-existing :parameter_mappings
+                                         (fn [pms]
+                                           (keep (fn [pm]
+                                                   (m/update-existing pm :card_id new-id))
+                                                 pms)))
+                      (m/update-existing :series
+                                         (fn [series]
+                                           (keep (fn [card]
+                                                   (when-let [id' (new-id (:id card))]
+                                                     (assoc card :id id')))
+                                                 series)))))))
+            ordered-cards))))
 
 (api/defendpoint POST "/:from-dashboard-id/copy"
   "Copy a Dashboard."
@@ -351,12 +366,16 @@
                         (let [dash (first (t2/insert-returning-instances! :model/Dashboard dashboard-data))
                               {id->new-card :copied uncopied :uncopied}
                               (when is_deep_copy
-                                (duplicate-cards existing-dashboard collection_id))]
+                                (duplicate-cards existing-dashboard collection_id))
+
+                              id->new-tab-id (when-let [existing-tabs (seq (:ordered_tabs existing-dashboard))]
+                                               (duplicate-tabs dash existing-tabs))]
                           (reset! new-cards (vals id->new-card))
                           (when-let [dashcards (seq (update-cards-for-copy from-dashboard-id
                                                                            (:ordered_cards existing-dashboard)
                                                                            is_deep_copy
-                                                                           id->new-card))]
+                                                                           id->new-card
+                                                                           id->new-tab-id))]
                             (api/check-500 (dashboard/add-dashcards! dash dashcards)))
                           (cond-> dash
                             (seq uncopied)
diff --git a/test/metabase/api/dashboard_test.clj b/test/metabase/api/dashboard_test.clj
index 58c7e9324d1ab417ad33110a02707761b36ecf82..aa7736fd67ee3f2b9650bdcb68edbe511f61a199 100644
--- a/test/metabase/api/dashboard_test.clj
+++ b/test/metabase/api/dashboard_test.clj
@@ -127,6 +127,38 @@
 (defmacro ^:private with-dashboards-in-writeable-collection [dashboards-or-ids & body]
   `(do-with-dashboards-in-a-collection perms/grant-collection-readwrite-permissions! ~dashboards-or-ids (fn [] ~@body)))
 
+(defn- do-with-simple-dashboard-with-tabs
+  [f]
+  (t2.with-temp/with-temp
+    [Dashboard           {dashboard-id :id} {}
+
+     Card                {card-id-1 :id}    {}
+
+     Card                {card-id-2 :id}    {}
+     :model/DashboardTab {dashtab-id-1 :id} {:name         "Tab 1"
+                                             :dashboard_id dashboard-id
+                                             :position     0}
+     :model/DashboardTab {dashtab-id-2 :id} {:name         "Tab 2"
+                                             :dashboard_id dashboard-id
+                                             :position     1}
+     DashboardCard       {dashcard-id-1 :id} {:dashboard_id     dashboard-id
+                                              :card_id          card-id-1
+                                              :dashboard_tab_id dashtab-id-1}
+     DashboardCard       {dashcard-id-2 :id} {:dashboard_id     dashboard-id
+                                              :card_id          card-id-2
+                                              :dashboard_tab_id dashtab-id-2}]
+    (f {:dashboard-id  dashboard-id
+        :card-id-1     card-id-1
+        :card-id-2     card-id-1
+        :dashtab-id-1  dashtab-id-1
+        :dashtab-id-2  dashtab-id-2
+        :dashcard-id-1 dashcard-id-1
+        :dashcard-id-2 dashcard-id-2})))
+
+(defmacro ^:private with-simple-dashboard-with-tabs
+  "Create a simple dashboard with 2 tabs and 2 cards in each tab and run `body` with the dashboard and cards ids bound to"
+  [[bindings] & body]
+  `(do-with-simple-dashboard-with-tabs (fn [~bindings] ~@body)))
 
 ;;; +----------------------------------------------------------------------------------------------------------------+
 ;;; |                                     /api/dashboard/* AUTHENTICATION Tests                                      |
@@ -868,6 +900,7 @@
                 "The copy should have a new entity ID generated")
             (finally
               (t2/delete! Dashboard :id (u/the-id response))))))))
+
   (testing "Deep copy: POST /api/dashboard/:id/copy"
     (mt/dataset sample-dataset
       (mt/with-temp* [Collection [source-coll {:name "Source collection"}]
@@ -1095,6 +1128,31 @@
                      (set (map :name cards-in-coll)))
                   "Cards should have \"-- Duplicate\" appended"))))))))
 
+(deftest copy-dashboard-with-tab-test
+  (testing "POST /api/dashboard/:id/copy"
+    (testing "for a dashboard that has tabs"
+      (with-simple-dashboard-with-tabs [{:keys [dashboard-id]}]
+        (let [new-dash-id        (:id (mt/user-http-request :rasta :post 200
+                                                            (format "dashboard/%d/copy" dashboard-id)
+                                                            {:name        "New dashboard"
+                                                             :description "A new description"}))
+              original-tabs      (t2/select [:model/DashboardTab :id :position :name]
+                                            :dashboard_id dashboard-id
+                                            {:order-by [[:position :asc]]})
+              new-tabs           (t2/select [:model/DashboardTab :id :position :name]
+                                            :dashboard_id new-dash-id
+                                            {:order-by [[:position :asc]]})
+              new->old-tab-id   (zipmap (map :id new-tabs) (map :id original-tabs))]
+         (testing "Cards are located correctly between tabs"
+                     (is (= (map #(select-keys % [:name :display :dashboard_tab_id]) (dashboard/ordered-cards dashboard-id))
+                            (map #(select-keys % [:name :display :dashboard_tab_id])
+                                 (for [card (dashboard/ordered-cards new-dash-id)]
+                                   (assoc card :dashboard_tab_id (new->old-tab-id (:dashboard_tab_id card))))))))
+
+         (testing "new tabs should have the same name and position"
+           (is (= (map #(dissoc % :id) original-tabs)
+                  (map #(dissoc % :id) new-tabs)))))))))
+
 (def ^:dynamic ^:private
   ^{:doc "Set of ids that will report [[mi/can-write]] as true."}
   *readable-card-ids* #{})
@@ -1140,14 +1198,24 @@
 
 (deftest update-cards-for-copy-test
   (testing "When copy style is shallow returns original ordered-cards"
-
     (let [ordered-cards [{:card_id 1 :card {:id 1} :series [{:id 2}]}
                          {:card_id 3 :card {:id 3}}]]
       (is (= ordered-cards
              (api.dashboard/update-cards-for-copy 1
                                                   ordered-cards
                                                   false
-                                                  nil)))))
+                                                  nil
+                                                  nil))))
+    (testing "with tab-ids updated if dashboard has tab"
+      (is (= [{:card_id 1 :card {:id 1} :dashboard_tab_id 10}
+              {:card_id 3 :card {:id 3} :dashboard_tab_id 20}]
+             (api.dashboard/update-cards-for-copy 1
+                                                  [{:card_id 1 :card {:id 1} :dashboard_tab_id 1}
+                                                   {:card_id 3 :card {:id 3} :dashboard_tab_id 2}]
+                                                  false
+                                                  nil
+                                                  {1 10
+                                                   2 20})))))
   (testing "When copy style is deep"
     (let [ordered-cards [{:card_id 1 :card {:id 1} :series [{:id 2} {:id 3}]}]]
       (testing "Can omit series cards"
@@ -1156,7 +1224,8 @@
                                                     ordered-cards
                                                     true
                                                     {1 {:id 5}
-                                                     2 {:id 6}})))))
+                                                     2 {:id 6}}
+                                                    nil)))))
     (testing "Can omit whole card with series if not copied"
       (let [ordered-cards [{:card_id 1 :card {} :series [{:id 2} {:id 3}]}
                            {:card_id 4 :card {} :series [{:id 5} {:id 6}]}]]
@@ -1169,7 +1238,8 @@
                                                      3 {:id 9}
                                                      ;; not copying id 4 which is the base of the following two
                                                      5 {:id 10}
-                                                     6 {:id 11}})))))
+                                                     6 {:id 11}}
+                                                    nil)))))
     (testing "Updates parameter mappings to new card ids"
       (let [ordered-cards [{:card_id            1
                             :card               {:id 1}
@@ -1186,7 +1256,8 @@
                (api.dashboard/update-cards-for-copy 1
                                                     ordered-cards
                                                     true
-                                                    {1 {:id 2}})))))
+                                                    {1 {:id 2}}
+                                                    nil)))))
     (testing "Throws error if no new card-id information for deep copy"
       (let [user-id      44
             dashboard-id 55
@@ -1195,6 +1266,7 @@
                              (api.dashboard/update-cards-for-copy dashboard-id
                                                                   [{:card_id 1 :card {:id 1}}]
                                                                   true
+                                                                  nil
                                                                   nil))
                            (is false "Should have thrown with deep-copy true and no new card id info")
                            (catch Exception e (ex-data e)))]
@@ -1317,40 +1389,6 @@
                                                              (format "dashboard/%d/cards" dashboard-id)
                                                              {:cards        [new-dashcard-info]
                                                               :ordered_tabs []}))}))))))
-
-(defn- do-with-simple-dashboard-with-tabs
-  [f]
-  (t2.with-temp/with-temp
-    [Dashboard           {dashboard-id :id} {}
-
-     Card                {card-id-1 :id}    {}
-
-     Card                {card-id-2 :id}    {}
-     :model/DashboardTab {dashtab-id-1 :id} {:name         "Tab 1"
-                                             :dashboard_id dashboard-id
-                                             :position     0}
-     :model/DashboardTab {dashtab-id-2 :id} {:name         "Tab 2"
-                                             :dashboard_id dashboard-id
-                                             :position     1}
-     DashboardCard       {dashcard-id-1 :id} {:dashboard_id     dashboard-id
-                                              :card_id          card-id-1
-                                              :dashboard_tab_id dashtab-id-1}
-     DashboardCard       {dashcard-id-2 :id} {:dashboard_id     dashboard-id
-                                              :card_id          card-id-2
-                                              :dashboard_tab_id dashtab-id-2}]
-    (f {:dashboard-id  dashboard-id
-        :card-id-1     card-id-1
-        :card-id-2     card-id-1
-        :dashtab-id-1  dashtab-id-1
-        :dashtab-id-2  dashtab-id-2
-        :dashcard-id-1 dashcard-id-1
-        :dashcard-id-2 dashcard-id-2})))
-
-(defmacro ^:private with-simple-dashboard-with-tabs
-  "Create a simple dashboard with 2 tabs and 2 cards in each tab and run `body` with the dashboard and cards ids bound to"
-  [[bindings] & body]
-  `(do-with-simple-dashboard-with-tabs (fn [~bindings] ~@body)))
-
 (deftest e2e-update-cards-and-tabs-test
   (testing "PUT /api/dashboard/:id/cards with create/update/delete in a single req"
        (t2.with-temp/with-temp