diff --git a/lib/private/DB/MigrationService.php b/lib/private/DB/MigrationService.php
index cd0280162d3826bb495c40df83e24ed16d7dba43..9c94cbc61fa71f5ca6708a9441058e3464c7aecc 100644
--- a/lib/private/DB/MigrationService.php
+++ b/lib/private/DB/MigrationService.php
@@ -124,6 +124,11 @@ class MigrationService {
 			return false;
 		}
 
+		if ($this->connection->tableExists('migrations')) {
+			$this->migrationTableCreated = true;
+			return false;
+		}
+
 		$schema = new SchemaWrapper($this->connection);
 
 		/**
@@ -408,6 +413,11 @@ class MigrationService {
 	 * @throws \InvalidArgumentException
 	 */
 	public function migrate($to = 'latest', $schemaOnly = false) {
+		if ($schemaOnly) {
+			$this->migrateSchemaOnly($to);
+			return;
+		}
+
 		// read known migrations
 		$toBeExecuted = $this->getMigrationsToExecute($to);
 		foreach ($toBeExecuted as $version) {
@@ -415,6 +425,42 @@ class MigrationService {
 		}
 	}
 
+	/**
+	 * Applies all not yet applied versions up to $to
+	 *
+	 * @param string $to
+	 * @throws \InvalidArgumentException
+	 */
+	public function migrateSchemaOnly($to = 'latest') {
+		// read known migrations
+		$toBeExecuted = $this->getMigrationsToExecute($to);
+
+		if (empty($toBeExecuted)) {
+			return;
+		}
+
+		$toSchema = null;
+		foreach ($toBeExecuted as $version) {
+			$instance = $this->createInstance($version);
+
+			$toSchema = $instance->changeSchema($this->output, function () use ($toSchema) {
+				return $toSchema ?: new SchemaWrapper($this->connection);
+			}, ['tablePrefix' => $this->connection->getPrefix()]) ?: $toSchema;
+
+			$this->markAsExecuted($version);
+		}
+
+		if ($toSchema instanceof SchemaWrapper) {
+			$targetSchema = $toSchema->getWrappedSchema();
+			if ($this->checkOracle) {
+				$beforeSchema = $this->connection->createSchema();
+				$this->ensureOracleIdentifierLengthLimit($beforeSchema, $targetSchema, strlen($this->connection->getPrefix()));
+			}
+			$this->connection->migrateToSchema($targetSchema);
+			$toSchema->performDropTableCalls();
+		}
+	}
+
 	/**
 	 * Get the human readable descriptions for the migration steps to run
 	 *
diff --git a/lib/private/Installer.php b/lib/private/Installer.php
index 9388711697a85b60e13c61f2ad77b6315bb8d170..96f14933a762b0f09b1c5fc076780463a70a0ff7 100644
--- a/lib/private/Installer.php
+++ b/lib/private/Installer.php
@@ -154,7 +154,7 @@ class Installer {
 			}
 		} else {
 			$ms = new \OC\DB\MigrationService($info['id'], \OC::$server->getDatabaseConnection());
-			$ms->migrate();
+			$ms->migrate('latest', true);
 		}
 		if ($previousVersion) {
 			OC_App::executeRepairSteps($appId, $info['repair-steps']['post-migration']);
@@ -589,7 +589,7 @@ class Installer {
 			}
 		} else {
 			$ms = new \OC\DB\MigrationService($app, \OC::$server->getDatabaseConnection());
-			$ms->migrate();
+			$ms->migrate('latest', true);
 		}
 
 		//run appinfo/install.php
diff --git a/lib/private/Setup/AbstractDatabase.php b/lib/private/Setup/AbstractDatabase.php
index 98d6b84ab9cf3c117c2fb2665fa9ad95ba9f4f1b..8a9aed09f1bc8814b440e898a4a116f33222bdb4 100644
--- a/lib/private/Setup/AbstractDatabase.php
+++ b/lib/private/Setup/AbstractDatabase.php
@@ -150,6 +150,6 @@ abstract class AbstractDatabase {
 			return;
 		}
 		$ms = new MigrationService('core', \OC::$server->getDatabaseConnection());
-		$ms->migrate();
+		$ms->migrate('latest', true);
 	}
 }