diff --git a/core/Common.php b/core/Common.php
index 670c25174f768f4fa9e4e494c2a64f217368b323..858c9fce288c274654624cb8697dbc9e8a1d254c 100644
--- a/core/Common.php
+++ b/core/Common.php
@@ -128,6 +128,18 @@ class Common
         (!strncmp(PHP_SAPI, 'cgi', 3) && empty($remoteAddr));
     }
 
+    /**
+     * Returns true if the current request is a console command, eg. ./console xx:yy
+     * @return bool
+     */
+    public static function isRunningConsoleCommand()
+    {
+        $searched = '/console';
+        $consolePos = strpos($_SERVER['SCRIPT_NAME'], $searched);
+        $expectedConsolePos = strlen($_SERVER['SCRIPT_NAME']) - strlen($searched);
+        $isScriptIsConsole = $consolePos == $expectedConsolePos;
+        return self::isPhpCliMode() && $isScriptIsConsole;
+    }
 
     /*
      * String operations
diff --git a/core/Updater.php b/core/Updater.php
index f63131aeb1a2764c0fb37b845d65c1990a21312e..59587cb19b883d22e38ea2c13751e0388e035380 100644
--- a/core/Updater.php
+++ b/core/Updater.php
@@ -126,9 +126,9 @@ class Updater
                 $this->hasMajorDbUpdate = $this->hasMajorDbUpdate || call_user_func(array($className, 'isMajorUpdate'));
             }
             // unfortunately had to extract this query from the Option class
-            $queries[] = 'UPDATE `' . Common::prefixTable('option') . '`
-    				SET option_value = \'' . $fileVersion . '\'
-    				WHERE option_name = \'' . self::getNameInOptionTable($componentName) . '\';';
+            $queries[] = 'UPDATE `' . Common::prefixTable('option') . '` '.
+    				'SET option_value = \'' . $fileVersion . '\' '.
+    				'WHERE option_name = \'' . self::getNameInOptionTable($componentName) . '\';';
         }
         return $queries;
     }
diff --git a/core/Url.php b/core/Url.php
index c023228fac3fbeca670957155811aaf4ee5c7a21..26e4249ec3e0d05e37acf4dd196a50e280acec52 100644
--- a/core/Url.php
+++ b/core/Url.php
@@ -469,6 +469,10 @@ class Url
         } else {
             echo "Invalid URL to redirect to.";
         }
+
+        if(Common::isPhpCliMode()) {
+            die("If you were using a browser, Piwik would redirect you to this URL: $url \n\n");
+        }
         exit;
     }
 
diff --git a/core/Version.php b/core/Version.php
index e07a0f49ad5af3f77780c79c69e4ceb18302efd2..40309b41b4587f0ee655c69dedfc319772b552f1 100644
--- a/core/Version.php
+++ b/core/Version.php
@@ -21,5 +21,5 @@ final class Version
      * The current Piwik version.
      * @var string
      */
-    const VERSION = '2.1-rc5';
+    const VERSION = '2.1-rc6';
 }
diff --git a/plugins/CoreUpdater/Commands/Update.php b/plugins/CoreUpdater/Commands/Update.php
new file mode 100644
index 0000000000000000000000000000000000000000..226117df1ef5987897bafb3841c66c469a41cbf1
--- /dev/null
+++ b/plugins/CoreUpdater/Commands/Update.php
@@ -0,0 +1,61 @@
+<?php
+/**
+ * Piwik - Open source web analytics
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ */
+namespace Piwik\Plugins\CoreUpdater\Commands;
+
+use Piwik\Plugin\ConsoleCommand;
+use Piwik\Plugins\CoreUpdater\Controller;
+use Piwik\Plugins\CoreUpdater\NoUpdatesFoundException;
+use Piwik\Plugins\UserCountry\LocationProvider;
+use Symfony\Component\Console\Input\ArrayInput;
+use Symfony\Component\Console\Input\InputArgument;
+use Symfony\Component\Console\Input\InputDefinition;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Input\InputOption;
+use Symfony\Component\Console\Output\OutputInterface;
+
+/**
+ * @package CloudAdmin
+ */
+class Update extends ConsoleCommand
+{
+    protected function configure()
+    {
+        $this->setName('core:update');
+        $this->setDescription('Triggers the upgrades for Piwik core and plugins. Useful after Piwik core files or some plugins were updated to latest files.');
+
+        $this->addOption('dry-run', null, InputOption::VALUE_NONE, 'Only prints out the SQL requests that would be executed during the upgrade');
+    }
+
+    /**
+     * Execute command like: ./console core:update --dry-run
+     */
+    protected function execute(InputInterface $input, OutputInterface $output)
+    {
+        $doDryRun = $input->getOption('dry-run');
+
+        try {
+            $this->makeUpdate($input, $output, $doDryRun);
+        } catch(NoUpdatesFoundException $e) {
+            // Do not fail if no updates were found
+            $output->writeln("<info>".$e->getMessage()."</info>");
+        } catch (\Exception $e) {
+            // Fail in case of any other error during upgrade
+            $output->writeln("<error>" . $e->getMessage() . "</error>");
+            throw $e;
+        }
+    }
+
+    protected function makeUpdate(InputInterface $input, OutputInterface $output, $doDryRun)
+    {
+        $this->checkAllRequiredOptionsAreNotEmpty($input);
+
+        $updateController = new Controller();
+        echo $updateController->runUpdaterAndExit($doDryRun);
+    }
+}
\ No newline at end of file
diff --git a/plugins/CoreUpdater/Controller.php b/plugins/CoreUpdater/Controller.php
index ab578bad5c308c42e1020415ee39a309e02797ad..f9369896fbbf7927754780138bbbd31a9fd380a5 100644
--- a/plugins/CoreUpdater/Controller.php
+++ b/plugins/CoreUpdater/Controller.php
@@ -13,6 +13,7 @@ use Piwik\API\Request;
 use Piwik\ArchiveProcessor\Rules;
 use Piwik\Common;
 use Piwik\Config;
+use Piwik\DataTable\Renderer\Console;
 use Piwik\DbHelper;
 use Piwik\Filechecks;
 use Piwik\Filesystem;
@@ -265,15 +266,19 @@ class Controller extends \Piwik\Plugin\Controller
             LanguagesManager::setLanguageForSession($language);
         }
 
-        return $this->runUpdaterAndExit();
+        try {
+            return $this->runUpdaterAndExit();
+        } catch(NoUpdatesFoundException $e) {
+            Piwik::redirectToModule('CoreHome');
+        }
     }
 
-    protected function runUpdaterAndExit()
+    public function runUpdaterAndExit($doDryRun = null)
     {
         $updater = new Updater();
         $componentsWithUpdateFile = CoreUpdater::getComponentUpdates($updater);
         if (empty($componentsWithUpdateFile)) {
-            Piwik::redirectToModule('CoreHome');
+            throw new NoUpdatesFoundException("Everything is already up to date.");
         }
 
         SettingsServer::setMaxExecutionTime(0);
@@ -283,33 +288,44 @@ class Controller extends \Piwik\Plugin\Controller
         $doneTemplate = '@CoreUpdater/runUpdaterAndExit_done' . $cli;
         $viewWelcome = new View($welcomeTemplate);
         $viewDone = new View($doneTemplate);
+        $doExecuteUpdates = Common::getRequestVar('updateCorePlugins', 0, 'integer') == 1;
+
+        if(is_null($doDryRun)) {
+            $doDryRun = !$doExecuteUpdates;
+        }
+
+        if($doDryRun) {
+            $viewWelcome->queries = $updater->getSqlQueriesToExecute();
+            $viewWelcome->isMajor = $updater->hasMajorDbUpdate();
+            $this->doWelcomeUpdates($viewWelcome, $componentsWithUpdateFile);
+            return $viewWelcome->render();
+        }
 
+        // CLI
         if (Common::isPhpCliMode()) {
             $this->doWelcomeUpdates($viewWelcome, $componentsWithUpdateFile);
             $output = $viewWelcome->render();
 
-            if (!$this->coreError && Piwik::getModule() == 'CoreUpdater') {
+            // Proceed with upgrade in CLI only if user specifically asked for it, or if running console command
+            $isUpdateRequested = Common::isRunningConsoleCommand() || Piwik::getModule() == 'CoreUpdater';
+
+            if (!$this->coreError && $isUpdateRequested) {
                 $this->doExecuteUpdates($viewDone, $updater, $componentsWithUpdateFile);
                 $output .= $viewDone->render();
             }
-
             return $output;
+        }
 
-        } else {
-            if (Common::getRequestVar('updateCorePlugins', 0, 'integer') == 1) {
-                $this->warningMessages = array();
-                $this->doExecuteUpdates($viewDone, $updater, $componentsWithUpdateFile);
+        // Web
+        if ($doExecuteUpdates) {
+            $this->warningMessages = array();
+            $this->doExecuteUpdates($viewDone, $updater, $componentsWithUpdateFile);
 
-                $this->redirectToDashboardWhenNoError($updater);
+            $this->redirectToDashboardWhenNoError($updater);
 
-                return $viewDone->render();
-            } else {
-                $viewWelcome->queries = $updater->getSqlQueriesToExecute();
-                $viewWelcome->isMajor = $updater->hasMajorDbUpdate();
-                $this->doWelcomeUpdates($viewWelcome, $componentsWithUpdateFile);
-                return $viewWelcome->render();
-            }
+            return $viewDone->render();
         }
+
         exit;
     }
 
diff --git a/plugins/CoreUpdater/CoreUpdater.php b/plugins/CoreUpdater/CoreUpdater.php
index 4593c42a06cd1471b34baf5bee054e6550cda796..8cde10a7bcb546518ccc4fb15bde15ac40a6a915 100644
--- a/plugins/CoreUpdater/CoreUpdater.php
+++ b/plugins/CoreUpdater/CoreUpdater.php
@@ -32,10 +32,16 @@ class CoreUpdater extends \Piwik\Plugin
         $hooks = array(
             'Request.dispatchCoreAndPluginUpdatesScreen' => 'dispatch',
             'Updater.checkForUpdates'                    => 'updateCheck',
+            'Console.addCommands'                        => 'addConsoleCommands',
         );
         return $hooks;
     }
 
+    public function addConsoleCommands(&$commands)
+    {
+        $commands[] = 'Piwik\Plugins\CoreUpdater\Commands\Update';
+    }
+
     public static function updateComponents(Updater $updater, $componentsWithUpdateFile)
     {
         $warnings = array();
diff --git a/plugins/CoreUpdater/NoUpdatesFoundException.php b/plugins/CoreUpdater/NoUpdatesFoundException.php
new file mode 100644
index 0000000000000000000000000000000000000000..1fd3ef116047ae5b430a245d7d29dadbfb35c685
--- /dev/null
+++ b/plugins/CoreUpdater/NoUpdatesFoundException.php
@@ -0,0 +1,13 @@
+<?php
+/**
+ * Piwik - Open source web analytics
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ */
+namespace Piwik\Plugins\CoreUpdater;
+
+class NoUpdatesFoundException extends \Exception {
+
+}
\ No newline at end of file
diff --git a/plugins/CoreUpdater/templates/runUpdaterAndExit_done_cli.twig b/plugins/CoreUpdater/templates/runUpdaterAndExit_done_cli.twig
index 9d1a5ae357a17affc198bc3adf1af9afa3624e50..3f6f2cd6f399c9c5f891e98368f859e5a6879e02 100644
--- a/plugins/CoreUpdater/templates/runUpdaterAndExit_done_cli.twig
+++ b/plugins/CoreUpdater/templates/runUpdaterAndExit_done_cli.twig
@@ -47,7 +47,7 @@
 
     * {{ helpMessage }}
 {% else %}
-    {{ 'CoreUpdater_PiwikHasBeenSuccessfullyUpgraded'|translate }}
+*** {{ 'CoreUpdater_PiwikHasBeenSuccessfullyUpgraded'|translate }} ***
 {% endif %}
 
 {% endif %}
diff --git a/plugins/CoreUpdater/templates/runUpdaterAndExit_welcome_cli.twig b/plugins/CoreUpdater/templates/runUpdaterAndExit_welcome_cli.twig
index 7ab452913e542b55e041f0ee4f3977cf7dea89ba..b9126329719ebf773ec456698db8ceb75d70527f 100644
--- a/plugins/CoreUpdater/templates/runUpdaterAndExit_welcome_cli.twig
+++ b/plugins/CoreUpdater/templates/runUpdaterAndExit_welcome_cli.twig
@@ -22,16 +22,27 @@
 
     {{ 'CoreUpdater_YourDatabaseIsOutOfDate'|translate }}
 
-    {% if coreToUpdate %}
-        {{ 'CoreUpdater_PiwikWillBeUpgradedFromVersionXToVersionY'|translate(current_piwik_version, new_piwik_version) }}
-    {% endif %}
+{% if coreToUpdate %}
+    {{ 'CoreUpdater_PiwikWillBeUpgradedFromVersionXToVersionY'|translate(current_piwik_version, new_piwik_version) }}
+{% endif %}
 
-    {% if pluginNamesToUpdate|length > 0 %}
-        {%- set listOfPlugins %}{{  pluginNamesToUpdate|implode(', ') }}{% endset %}
-        {{ 'CoreUpdater_TheFollowingPluginsWillBeUpgradedX'|translate( listOfPlugins) }}
-    {%  endif %}
+{%- if pluginNamesToUpdate|length > 0 %}
+    {%- set listOfPlugins %}{{  pluginNamesToUpdate|implode(', ') }}{% endset %}
+    {{ 'CoreUpdater_TheFollowingPluginsWillBeUpgradedX'|translate( listOfPlugins) }}
+{%  endif %}
+
+{# dry run #}
+{% if queries is defined and queries is not empty %}
+*** Note: this is a Dry Run ***
 
+    {% for query in queries %}{{ query|trim }}
+    {% endfor %}
+
+*** End of Dry Run ***
+{% else %}
     {{ 'CoreUpdater_TheUpgradeProcessMayTakeAWhilePleaseBePatient'|translate }}
+{% endif %}
+
 {%  endif %}
 {% endautoescape %}