diff --git a/src/metabase/core.clj b/src/metabase/core.clj
index c068c4d4a47043b0a879af9fd3e261694674edb7..0bd1eb1d6f4851a2cb954c8b28fc3d7b0941e983 100644
--- a/src/metabase/core.clj
+++ b/src/metabase/core.clj
@@ -21,7 +21,8 @@
                       [middleware :as mb-middleware]
                       [routes :as routes]
                       [setup :as setup]
-                      [task :as task])
+                      [task :as task]
+                      [util :as u])
             (metabase.models [setting :refer [defsetting]]
                              [database :refer [Database]]
                              [user :refer [User]])))
@@ -177,10 +178,7 @@
       (catch Throwable e
         (log/error (format "Failed to load sample dataset: %s" (.getMessage e)))))))
 
-
-(defn -main
-  "Launch Metabase in standalone mode."
-  [& args]
+(defn- start-normally []
   (log/info "Starting Metabase in STANDALONE mode")
   (try
     ;; run our initialization process
@@ -192,3 +190,21 @@
     (catch Exception e
       (.printStackTrace e)
       (log/error "Metabase Initialization FAILED: " (.getMessage e)))))
+
+(defn- run-cmd [cmd & args]
+  (let [cmd->fn {:migrate (fn [direction]
+                            (db/migrate (keyword direction)))}]
+    (if-let [f (cmd->fn cmd)]
+      (do (apply f args)
+          (println "Success.")
+          (System/exit 0))
+      (do (println "Unrecognized command:" (name cmd))
+          (println "Valid commands are:\n" (u/pprint-to-str (map name (keys cmd->fn))))
+          (System/exit 1)))))
+
+(defn -main
+  "Launch Metabase in standalone mode."
+  [& [cmd & args]]
+  (if cmd
+    (apply run-cmd (keyword cmd) args) ; run a command like `java -jar metabase.jar migrate release-locks` or `lein run migrate release-locks`
+    (start-normally)))                 ; with no command line args just start Metabase normally
diff --git a/src/metabase/db.clj b/src/metabase/db.clj
index b10bca61cb3c577d442862e25ab29c1c1f7c89f2..492594f028863afeb2ee914fbf13e8f7093853f3 100644
--- a/src/metabase/db.clj
+++ b/src/metabase/db.clj
@@ -64,21 +64,31 @@
   "migrations/liquibase.json")
 
 (defn migrate
-  "Migrate the database `:up`, `:down`, or `:print`."
-  [jdbc-connection-details direction]
-  (try
-    (jdbc/with-db-transaction [conn jdbc-connection-details]
-      (let [^Database  database  (-> (DatabaseFactory/getInstance)
-                                     (.findCorrectDatabaseImplementation (JdbcConnection. (jdbc/get-connection conn))))
-            ^Liquibase liquibase (Liquibase. changelog-file (ClassLoaderResourceAccessor.) database)]
-        (case direction
-          :up    (.update liquibase "")
-          :down  (.rollback liquibase 10000 "")
-          :print (let [writer (StringWriter.)]
-                   (.update liquibase "" writer)
-                   (.toString writer)))))
-    (catch Throwable e
-      (throw (DatabaseException. e)))))
+  "Migrate the database:
+
+   *  `:up`            - Migrate up
+   *  `:down`          - Rollback *all* migrations
+   *  `:print`         - Just print the SQL for running the migrations, don't actually run them.
+   *  `:release-locks` - Manually release migration locks left by an earlier failed migration.
+                         (This shouldn't be necessary now that we run migrations inside a transaction,
+                         but is available just in case)."
+  ([direction]
+   (migrate @jdbc-connection-details direction))
+  ([jdbc-connection-details direction]
+   (try
+     (jdbc/with-db-transaction [conn jdbc-connection-details]
+       (let [^Database  database  (-> (DatabaseFactory/getInstance)
+                                      (.findCorrectDatabaseImplementation (JdbcConnection. (jdbc/get-connection conn))))
+             ^Liquibase liquibase (Liquibase. changelog-file (ClassLoaderResourceAccessor.) database)]
+         (case direction
+           :up            (.update liquibase "")
+           :down          (.rollback liquibase 10000 "")
+           :print         (let [writer (StringWriter.)]
+                            (.update liquibase "" writer)
+                            (.toString writer))
+           :release-locks (.forceReleaseLocks liquibase))))
+     (catch Throwable e
+       (throw (DatabaseException. e))))))
 
 
 ;; ## SETUP-DB
@@ -122,10 +132,10 @@
 
   ;; Run through our DB migration process and make sure DB is fully prepared
   (if auto-migrate
-    (migrate @jdbc-connection-details :up)
+    (migrate :up)
     ;; if we are not doing auto migrations then print out migration sql for user to run manually
     ;; then throw an exception to short circuit the setup process and make it clear we can't proceed
-    (let [sql (migrate @jdbc-connection-details :print)]
+    (let [sql (migrate :print)]
       (log/info (str "Database Upgrade Required\n\n"
                      "NOTICE: Your database requires updates to work with this version of Metabase.  "
                      "Please execute the following sql commands on your database before proceeding.\n\n"