diff --git a/src/metabase/api/collection.clj b/src/metabase/api/collection.clj
index 8bda8bdf525a798a03dbde14a3d4689e33dfead2..e6772dc4fc0f14fefd31aa3ea95061175a474a8b 100644
--- a/src/metabase/api/collection.clj
+++ b/src/metabase/api/collection.clj
@@ -20,6 +20,7 @@
    [metabase.legacy-mbql.normalize :as mbql.normalize]
    [metabase.models.card :as card :refer [Card]]
    [metabase.models.collection :as collection :refer [Collection]]
+   [metabase.models.collection-permission-graph-revision :as c-perm-revision]
    [metabase.models.collection.graph :as graph]
    [metabase.models.collection.root :as collection.root]
    [metabase.models.interface :as mi]
@@ -1246,16 +1247,30 @@
   ;; TODO: should use a coercer for this?
   (graph-decoder permission-graph))
 
+(defn- update-graph!
+  "Handles updating the graph for a given namespace."
+  [namespace graph skip_graph]
+  (graph/update-graph! namespace graph)
+  (if skip_graph
+    {:revision (c-perm-revision/latest-id)}
+    (graph/graph namespace)))
+
 (api/defendpoint PUT "/graph"
   "Do a batch update of Collections Permissions by passing in a modified graph.
-  Will overwrite parts of the graph that are present in the request, and leave the rest unchanged."
-  [:as {{:keys [namespace], :as body} :body}]
-  {body      :map
-   namespace [:maybe ms/NonBlankString]}
+  Will overwrite parts of the graph that are present in the request, and leave the rest unchanged.
+
+  If the `skip_graph` query parameter is true, it will only return the current revision"
+  [:as {{:keys [namespace revision groups]} :body
+        {:strs [skip_graph]} :query-params}]
+  {namespace [:maybe ms/NonBlankString]
+   revision  ms/Int
+   groups :map
+   skip_graph [:maybe ms/BooleanValue]}
   (api/check-superuser)
-  (->> (dissoc body :namespace)
-       decode-graph
-       (graph/update-graph! namespace))
-  (graph/graph namespace))
+  (update-graph!
+   namespace
+   (decode-graph {:revision revision :groups groups})
+   skip_graph))
+
 
 (api/define-routes)
diff --git a/test/metabase/api/collection_test.clj b/test/metabase/api/collection_test.clj
index 0efbdcc068a863cb5f04ca57ac876b072f869604..f800c14beaab560e5120a509062010256d732906 100644
--- a/test/metabase/api/collection_test.clj
+++ b/test/metabase/api/collection_test.clj
@@ -11,6 +11,7 @@
             NativeQuerySnippet PermissionsGroup PermissionsGroupMembership Pulse
             PulseCard PulseChannel PulseChannelRecipient Revision Timeline TimelineEvent User]]
    [metabase.models.collection :as collection]
+   [metabase.models.collection-permission-graph-revision :as c-perm-revision]
    [metabase.models.collection-test :as collection-test]
    [metabase.models.collection.graph :as graph]
    [metabase.models.collection.graph-test :as graph.test]
@@ -2262,3 +2263,16 @@
     (testing "Cards can't be moved to the trash"
       (mt/user-http-request :crowberto :put 400 (str "card/" (u/the-id card)) {:collection_id (collection/trash-collection-id)})
       (is (not (t2/exists? :model/Card :collection_id (collection/trash-collection-id)))))))
+
+(deftest skip-graph-skips-graph-on-graph-PUT
+  (is (malli= [:map [:revision :int] [:groups :map]]
+              (mt/user-http-request :crowberto
+                                    :put 200
+                                    "collection/graph"
+                                    {:revision (c-perm-revision/latest-id) :groups {}})))
+  (is (malli= [:map {:closed true} [:revision :int]]
+              (mt/user-http-request :crowberto
+                                    :put 200
+                                    "collection/graph?skip_graph=true"
+                                    {:revision (c-perm-revision/latest-id) :groups {}}))
+      "PUTs with skip_graph should not return the coll permission graph."))
diff --git a/test/metabase/upload_test.clj b/test/metabase/upload_test.clj
index fc7c84a428ab6d71500d8dc3efa3d5eb9941feb6..fd0da663e43fa2a21e0eeb56c41b5a0aedfd6070 100644
--- a/test/metabase/upload_test.clj
+++ b/test/metabase/upload_test.clj
@@ -390,7 +390,7 @@
                         upload/max-bytes (constantly max-bytes)]
             (doseq [c ["a" "出"]]
               (let [long-csv-file-prefix (apply str (repeat (inc max-bytes) c))
-                    char-size            (count (.getBytes c "UTF-8"))]
+                    char-size            (count (.getBytes ^String c "UTF-8"))]
                 (with-upload-table! [table (card->table (upload-example-csv! :csv-file-prefix long-csv-file-prefix))]
                   (testing "The card name should be truncated to max bytes with UTF-8 encoding"
                     (is (= (str/capitalize (apply str (repeat (quot max-bytes char-size) c)))