diff --git a/lib/private/updater.php b/lib/private/updater.php
index f73fa8ff65566992c56aade1ab83cbd5f80fa844..0f9ecfe93de9da505c824713f0d27180d546070a 100644
--- a/lib/private/updater.php
+++ b/lib/private/updater.php
@@ -211,20 +211,47 @@ class Updater extends BasicEmitter {
 		return $success;
 	}
 
+	/**
+	 * Return version from which this version is allowed to upgrade from
+	 *
+	 * @return string allowed previous version
+	 */
+	private function getAllowedPreviousVersion() {
+		// this should really be a JSON file
+		require \OC::$SERVERROOT . '/version.php';
+		return implode('.', $OC_VersionCanBeUpgradedFrom);
+	}
+
 	/**
 	 * Whether an upgrade to a specified version is possible
 	 * @param string $oldVersion
 	 * @param string $newVersion
+	 * @param string $allowedPreviousVersion
 	 * @return bool
 	 */
-	public function isUpgradePossible($oldVersion, $newVersion) {
+	public function isUpgradePossible($oldVersion, $newVersion, $allowedPreviousVersion) {
+		// downgrade is never allowed
+		if (version_compare($oldVersion, $newVersion, '>')) {
+			return false;
+		}
+
 		$oldVersion = explode('.', $oldVersion);
 		$newVersion = explode('.', $newVersion);
 
-		if($newVersion[0] > ($oldVersion[0] + 1) || $oldVersion[0] > $newVersion[0]) {
-			return false;
+		while (count($oldVersion) > 2) {
+			array_pop($oldVersion);
+		}
+
+		while (count($newVersion) > 2) {
+			array_pop($newVersion);
 		}
-		return true;
+
+		$oldVersion = implode('.', $oldVersion);
+		$newVersion = implode('.', $newVersion);
+
+		// either we're updating from an allowed version or the current version
+		return (version_compare($allowedPreviousVersion, $oldVersion) === 0
+			|| version_compare($newVersion, $oldVersion) === 0);
 	}
 
 	/**
@@ -259,8 +286,9 @@ class Updater extends BasicEmitter {
 	 */
 	private function doUpgrade($currentVersion, $installedVersion) {
 		// Stop update if the update is over several major versions
-		if (!self::isUpgradePossible($installedVersion, $currentVersion)) {
-			throw new \Exception('Updates between multiple major versions are unsupported.');
+		$allowedPreviousVersion = $this->getAllowedPreviousVersion();
+		if (!self::isUpgradePossible($installedVersion, $currentVersion, $allowedPreviousVersion)) {
+			throw new \Exception('Updates between multiple major versions and downgrades are unsupported.');
 		}
 
 		// Update .htaccess files
diff --git a/tests/lib/updater.php b/tests/lib/updater.php
index 28577071b4c3cb35f3d8449ef81a3818cff93b0f..763858acf5d69599560ff57f85a782bca158d7f9 100644
--- a/tests/lib/updater.php
+++ b/tests/lib/updater.php
@@ -67,14 +67,68 @@ class UpdaterTest extends \Test\TestCase {
 	 */
 	public function versionCompatibilityTestData() {
 		return [
-			['1.0.0.0', '2.2.0', true],
-			['1.1.1.1', '2.0.0', true],
-			['5.0.3', '4.0.3', false],
-			['12.0.3', '13.4.5', true],
-			['1', '2', true],
-			['2', '2', true],
-			['6.0.5', '6.0.6', true],
-			['5.0.6', '7.0.4', false],
+			['1', '2', '1', true],
+			['2', '2', '2', true],
+			['6.0.5.0', '6.0.6.0', '5.0', true],
+			['5.0.6.0', '7.0.4.0', '6.0', false],
+			// allow upgrading within the same major release
+			['8.0.0.0', '8.0.0.0', '8.0', true],
+			['8.0.0.0', '8.0.0.4', '8.0', true],
+			['8.0.0.0', '8.0.1.0', '8.0', true],
+			['8.0.0.0', '8.0.2.0', '8.0', true],
+			// does not allow downgrading within the same major release
+			['8.0.1.0', '8.0.0.0', '8.0', false],
+			['8.0.2.0', '8.0.1.0', '8.0', false],
+			['8.0.0.4', '8.0.0.0', '8.0', false],
+			// allows upgrading within the patch version
+			['8.0.0.0', '8.0.0.1', '8.0', true],
+			['8.0.0.0', '8.0.0.2', '8.0', true],
+			// does not allow downgrading within the same major release
+			['8.0.0.1', '8.0.0.0', '8.0', false],
+			['8.0.0.2', '8.0.0.0', '8.0', false],
+			// allow upgrading to the next major release
+			['8.0.0.0', '8.1.0.0', '8.0', true],
+			['8.0.0.0', '8.1.1.0', '8.0', true],
+			['8.0.0.0', '8.1.1.5', '8.0', true],
+			['8.0.0.2', '8.1.1.5', '8.0', true],
+			['8.1.0.0', '8.2.0.0', '8.1', true],
+			['8.1.0.2', '8.2.0.4', '8.1', true],
+			['8.1.0.5', '8.2.0.1', '8.1', true],
+			['8.1.0.0', '8.2.1.0', '8.1', true],
+			['8.1.0.2', '8.2.1.5', '8.1', true],
+			['8.1.0.5', '8.2.1.1', '8.1', true],
+			// does not allow downgrading to the previous major release
+			['8.1.0.0', '8.0.0.0', '7.0', false],
+			['8.1.1.0', '8.0.0.0', '7.0', false],
+			// does not allow skipping major releases
+			['8.0.0.0', '8.2.0.0', '8.1', false],
+			['8.0.0.0', '8.2.1.0', '8.1', false],
+			['8.0.0.0', '9.0.1.0', '8.2', false],
+			['8.0.0.0', '10.0.0.0', '9.3', false],
+			// allows updating to the next major release
+			['8.2.0.0', '9.0.0.0', '8.2', true],
+			['8.2.0.0', '9.0.0.0', '8.2', true],
+			['8.2.0.0', '9.0.1.0', '8.2', true],
+			['8.2.0.0', '9.0.1.1', '8.2', true],
+			['8.2.0.2', '9.0.1.1', '8.2', true],
+			['8.2.2.0', '9.0.1.0', '8.2', true],
+			['8.2.2.2', '9.0.1.1', '8.2', true],
+			['9.0.0.0', '9.1.0.0', '9.0', true],
+			['9.0.0.0', '9.1.0.2', '9.0', true],
+			['9.0.0.2', '9.1.0.1', '9.0', true],
+			['9.1.0.0', '9.2.0.0', '9.1', true],
+			['9.2.0.0', '9.3.0.0', '9.2', true],
+			['9.3.0.0', '10.0.0.0', '9.3', true],
+			// does not allow updating to the next major release (first number)
+			['9.0.0.0', '8.2.0.0', '8.1', false],
+			// other cases
+			['8.0.0.0', '8.1.5.0', '8.0', true],
+			['8.2.0.0', '9.0.0.0', '8.2', true],
+			['8.2.0.0', '9.1.0.0', '9.0', false],
+			['9.0.0.0', '8.1.0.0', '8.0', false],
+			['9.0.0.0', '8.0.0.0', '7.0', false],
+			['9.1.0.0', '8.0.0.0', '7.0', false],
+			['8.2.0.0', '8.1.0.0', '8.0', false],
 		];
 	}
 
@@ -106,9 +160,9 @@ class UpdaterTest extends \Test\TestCase {
 	 * @param string $newVersion
 	 * @param bool $result
 	 */
-	public function testIsUpgradePossible($oldVersion, $newVersion, $result) {
+	public function testIsUpgradePossible($oldVersion, $newVersion, $allowedVersion, $result) {
 		$updater = new Updater($this->httpHelper, $this->config);
-		$this->assertSame($result, $updater->isUpgradePossible($oldVersion, $newVersion));
+		$this->assertSame($result, $updater->isUpgradePossible($oldVersion, $newVersion, $allowedVersion));
 	}
 
 	public function testCheckInCache() {
diff --git a/version.php b/version.php
index a115f4b26be3c8d0392d9f2e4679b39476e8e4e6..a6b49d9dc7419fb93cf25fbf4b0b25a11237950c 100644
--- a/version.php
+++ b/version.php
@@ -2,6 +2,7 @@
 /**
  * @author Frank Karlitschek <frank@owncloud.org>
  * @author Lukas Reschke <lukas@owncloud.com>
+ * @author Vincent Petry <pvince81@owncloud.com>
  *
  * @copyright Copyright (c) 2015, ownCloud, Inc.
  * @license AGPL-3.0
@@ -22,14 +23,16 @@
 // We only can count up. The 4. digit is only for the internal patchlevel to trigger DB upgrades
 // between betas, final and RCs. This is _not_ the public version number. Reset minor/patchlevel
 // when updating major/minor version number.
-$OC_Version=array(8, 2, 0, 4);
+$OC_Version = [8, 2, 0, 4];
 
 // The human readable string
-$OC_VersionString='8.2 pre alpha';
+$OC_VersionString = '8.2 pre alpha';
+
+$OC_VersionCanBeUpgradedFrom = [8, 1];
 
 // The ownCloud channel
-$OC_Channel='git';
+$OC_Channel = 'git';
 
 // The build number
-$OC_Build='';
+$OC_Build = '';