diff --git a/src/metabase/models/permissions.clj b/src/metabase/models/permissions.clj
index 50629f0df5910135d14c3f6e1bf40fb73a1f4b6c..ae749495e13aa891da9405956507a35ec9bd6a3d 100644
--- a/src/metabase/models/permissions.clj
+++ b/src/metabase/models/permissions.clj
@@ -302,9 +302,19 @@
                       (seq path))
              (re-matches path-regex path))))
 
+(defn valid-path-format?
+  "Is `path` a string with a valid permissions path format? This is a less strict version of [[valid-path?]] which
+  just checks that the path components contain alphanumeric characters or dashes, separated by slashes
+  This should be used for schema validation in most places, to preserve downgradability when new permissions paths are
+  added."
+  ^Boolean [^String path]
+  (boolean (when (and (string? path)
+                      (seq path))
+             (re-matches (re-pattern (str "^/(" path-char "*/)*$")) path))))
+
 (def Path
-  "Schema for a valid permissions path."
-  (s/pred valid-path? "Valid permissions path"))
+  "Schema for a permissions path with a valid format."
+  (s/pred valid-path-format? "Valid permissions path"))
 
 (defn- assert-not-admin-group
   "Check to make sure the `:group_id` for `permissions` entry isn't the admin group."
diff --git a/test/metabase/models/permissions_test.clj b/test/metabase/models/permissions_test.clj
index 39ed678fb60f111edcd4a67bb830551a22b7d89d..a5dcd170c2554b439406170a61c6402de0062211 100644
--- a/test/metabase/models/permissions_test.clj
+++ b/test/metabase/models/permissions_test.clj
@@ -14,54 +14,59 @@
 
 ;;; ----------------------------------------------- valid-path? -----------------------------------------------
 
+(def ^:private valid-paths
+  ["/db/1/"
+   "/db/1/native/"
+   "/db/1/schema/"
+   "/db/1/schema/public/"
+   "/db/1/schema/PUBLIC/"
+   "/db/1/schema//"
+   "/db/1/schema/1234/"
+   "/db/1/schema/public/table/1/"
+   "/db/1/schema/PUBLIC/table/1/"
+   "/db/1/schema//table/1/"
+   "/db/1/schema/public/table/1/"
+   "/db/1/schema/PUBLIC/table/1/"
+   "/db/1/schema//table/1/"
+   "/db/1/schema/1234/table/1/"
+   "/db/1/schema/PUBLIC/table/1/query/"
+   "/db/1/schema/PUBLIC/table/1/query/segmented/"
+   ;; download permissions
+   "/download/db/1/"
+   "/download/limited/db/1/"
+   "/download/db/1/native/"
+   "/download/limited/db/1/native/"
+   "/download/db/1/schema/PUBLIC/"
+   "/download/limited/db/1/schema/PUBLIC/"
+   "/download/db/1/schema/PUBLIC/table/1/"
+   "/download/limited/db/1/schema/PUBLIC/table/1/"
+   ;; block permissions
+   "/block/db/1/"
+   "/block/db/1000/"
+   ;; full admin (everything) root permissions
+   "/"])
+
+(def ^:private valid-paths-with-slashes
+  [;; COMPANY-NET\ should get escaped to COMPANY-NET\\
+   "/db/16/schema/COMPANY-NET\\\\john.doe/"
+   ;; COMPANY-NET/ should get escaped to COMPANY-NET\/
+   "/db/16/schema/COMPANY-NET\\/john.doe/"
+   ;; my\schema should get escaped to my\\schema
+   "/db/1/schema/my\\\\schema/table/1/"
+   ;; my\\schema should get escaped to my\\\\schema
+   "/db/1/schema/my\\\\\\\\schema/table/1/"
+   ;; my/schema should get escaped to my\/schema
+   "/db/1/schema/my\\/schema/table/1/"])
+
 (deftest valid-path-test
   (testing "valid paths"
-    (doseq [path
-            ["/db/1/"
-             "/db/1/native/"
-             "/db/1/schema/"
-             "/db/1/schema/public/"
-             "/db/1/schema/PUBLIC/"
-             "/db/1/schema//"
-             "/db/1/schema/1234/"
-             "/db/1/schema/public/table/1/"
-             "/db/1/schema/PUBLIC/table/1/"
-             "/db/1/schema//table/1/"
-             "/db/1/schema/public/table/1/"
-             "/db/1/schema/PUBLIC/table/1/"
-             "/db/1/schema//table/1/"
-             "/db/1/schema/1234/table/1/"
-             "/db/1/schema/PUBLIC/table/1/query/"
-             "/db/1/schema/PUBLIC/table/1/query/segmented/"
-             ;; download permissions
-             "/download/db/1/"
-             "/download/limited/db/1/"
-             "/download/db/1/native/"
-             "/download/limited/db/1/native/"
-             "/download/db/1/schema/PUBLIC/"
-             "/download/limited/db/1/schema/PUBLIC/"
-             "/download/db/1/schema/PUBLIC/table/1/"
-             "/download/limited/db/1/schema/PUBLIC/table/1/"
-             ;; block permissions
-             "/block/db/1/"
-             "/block/db/1000/"
-             ;; full admin (everything) root permissions
-             "/"]]
+    (doseq [path valid-paths]
       (testing (pr-str path)
         (is (= true
                (perms/valid-path? path)))))
 
     (testing "\nWe should allow slashes in permissions paths? (#8693, #13263)\n"
-      (doseq [path [;; COMPANY-NET\ should get escaped to COMPANY-NET\\
-                    "/db/16/schema/COMPANY-NET\\\\john.doe/"
-                    ;; COMPANY-NET/ should get escaped to COMPANY-NET\/
-                    "/db/16/schema/COMPANY-NET\\/john.doe/"
-                    ;; my\schema should get escaped to my\\schema
-                    "/db/1/schema/my\\\\schema/table/1/"
-                    ;; my\\schema should get escaped to my\\\\schema
-                    "/db/1/schema/my\\\\\\\\schema/table/1/"
-                    ;; my/schema should get escaped to my\/schema
-                    "/db/1/schema/my\\/schema/table/1/"]]
+      (doseq [path valid-paths-with-slashes]
         (testing (pr-str path)
           (is (= true
                  (perms/valid-path? path)))))))
@@ -193,6 +198,42 @@
           (is (= expected
                  (perms/valid-path? path))))))))
 
+(deftest valid-path-format-test
+  (testing "known valid paths"
+    (doseq [path (concat valid-paths valid-paths-with-slashes)]
+      (testing (pr-str path)
+        (is (= true
+               (perms/valid-path-format? path))))))
+
+  (testing "unknown paths with valid path format"
+    (doseq [path ["/asdf/"
+                  "/asdf/ghjk/"
+                  "/asdf-ghjk/"
+                  "/adsf//"
+                  "/asdf/1/ghkl/"
+                  "/asdf\\/ghkl/"
+                  "/asdf\\\\ghkl/"]]
+      (testing (pr-str path)
+        (is (= true
+               (perms/valid-path-format? path))))))
+
+  (testing "invalid paths"
+    (doseq [path
+            [""
+             "/asdf"
+             "asdf/"
+             "123"
+             nil
+             {}
+             []
+             true
+             false
+             (keyword "/asdf/")
+             1234]]
+      (testing (pr-str path)
+        (is (= false
+               (perms/valid-path-format? path)))))))
+
 
 ;;; -------------------------------------------------- data-perms-path ---------------------------------------------------