diff --git a/core/core.services.yml b/core/core.services.yml
index e161319..8d315eb 100644
--- a/core/core.services.yml
+++ b/core/core.services.yml
@@ -595,9 +595,14 @@ services:
     tags:
       - { name: access_check, applies_to: _csrf_token }
     arguments: ['@csrf_token']
+  site_status_negotiator:
+    class: Drupal\Core\Site\StatusNegotiator
+    arguments: ['@state', '@current_user']
+    tags:
+      - { name: service_collector, tag: maintenance_mode_exemption, call: addExemption }
   maintenance_mode_subscriber:
     class: Drupal\Core\EventSubscriber\MaintenanceModeSubscriber
-    arguments: ['@state', '@config.factory', '@string_translation', '@url_generator', '@current_user']
+    arguments: ['@site_status_negotiator', '@config.factory', '@string_translation', '@url_generator', '@current_user']
     tags:
       - { name: event_subscriber }
   path_subscriber:
diff --git a/core/lib/Drupal/Core/EventSubscriber/MaintenanceModeSubscriber.php b/core/lib/Drupal/Core/EventSubscriber/MaintenanceModeSubscriber.php
index 1b665f3..2c2f664 100644
--- a/core/lib/Drupal/Core/EventSubscriber/MaintenanceModeSubscriber.php
+++ b/core/lib/Drupal/Core/EventSubscriber/MaintenanceModeSubscriber.php
@@ -11,12 +11,13 @@
 use Drupal\Component\Utility\Xss;
 use Drupal\Core\Config\ConfigFactoryInterface;
 use Drupal\Core\Page\DefaultHtmlPageRenderer;
+use Drupal\Core\Routing\RouteMatch;
 use Drupal\Core\Routing\UrlGeneratorInterface;
 use Drupal\Core\Session\AccountInterface;
+use Drupal\Core\Site\StatusNegotiatorInterface;
 use Drupal\Core\State\StateInterface;
 use Drupal\Core\StringTranslation\StringTranslationTrait;
 use Drupal\Core\StringTranslation\TranslationInterface;
-use Symfony\Cmf\Component\Routing\RouteObjectInterface;
 use Symfony\Component\EventDispatcher\EventSubscriberInterface;
 use Symfony\Component\HttpFoundation\RedirectResponse;
 use Symfony\Component\HttpFoundation\Response;
@@ -31,18 +32,18 @@ class MaintenanceModeSubscriber implements EventSubscriberInterface {
   use StringTranslationTrait;
 
   /**
-   * The current account.
+   * The site status negotiator.
    *
-   * @var \Drupal\Core\Session\AccountInterface
+   * @var \Drupal\Core\Site\StatusNegotiatorInterface
    */
-  protected $account;
+  protected $statusNegotiator;
 
   /**
-   * The state.
+   * The current account.
    *
-   * @var \Drupal\Core\State\StateInterface
+   * @var \Drupal\Core\Session\AccountInterface
    */
-  protected $state;
+  protected $account;
 
   /**
    * The config factory.
@@ -59,30 +60,10 @@ class MaintenanceModeSubscriber implements EventSubscriberInterface {
   protected $urlGenerator;
 
   /**
-   * @defgroup menu_status_codes Menu status codes
-   * @{
-   * Status codes to be used to check the maintenance code.
-   */
-
-  /**
-   * Internal menu status code -- Menu item inaccessible because site is offline.
-   */
-  const SITE_OFFLINE = 4;
-
-  /**
-   * Internal menu status code -- Everything is working fine.
-   */
-  const SITE_ONLINE = 5;
-
-  /**
-   * @} End of "defgroup menu_status_codes".
-   */
-
-  /**
    * Constructs a new MaintenanceModeSubscriber.
    *
-   * @param \Drupal\Core\State\StateInterface $state
-   *   The state.
+   * @param \Drupal\Core\Site\StatusNegotiatorInterface $status_negotiator
+   *   The site status negotiator.
    * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
    *   The config factory.
    * @param \Drupal\Core\StringTranslation\TranslationInterface $translation
@@ -92,8 +73,8 @@ class MaintenanceModeSubscriber implements EventSubscriberInterface {
    * @param \Drupal\Core\Session\AccountInterface $account
    *   The current user.
    */
-  public function __construct(StateInterface $state, ConfigFactoryInterface $config_factory, TranslationInterface $translation, UrlGeneratorInterface $url_generator, AccountInterface $account) {
-    $this->state = $state;
+  public function __construct(StatusNegotiatorInterface $status_negotiator, ConfigFactoryInterface $config_factory, TranslationInterface $translation, UrlGeneratorInterface $url_generator, AccountInterface $account) {
+    $this->statusNegotiator = $status_negotiator;
     $this->config = $config_factory;
     $this->stringTranslation = $translation;
     $this->urlGenerator = $url_generator;
@@ -101,70 +82,40 @@ public function __construct(StateInterface $state, ConfigFactoryInterface $confi
   }
 
   /**
-   * Determine whether the page is configured to be offline.
-   *
-   * @param \Symfony\Component\HttpKernel\Event\GetResponseEvent $event
-   *   The Event to process.
-   */
-  public function onKernelRequestDetermineSiteStatus(GetResponseEvent $event) {
-    // Check if the site is offline.
-    $request = $event->getRequest();
-    $is_offline = $this->isSiteInMaintenance($request) ? static::SITE_OFFLINE : static::SITE_ONLINE;
-    $request->attributes->set('_maintenance', $is_offline);
-  }
-
-  /**
    * Returns the site maintenance page if the site is offline.
    *
    * @param \Symfony\Component\HttpKernel\Event\GetResponseEvent $event
    *   The event to process.
    */
   public function onKernelRequestMaintenance(GetResponseEvent $event) {
-    $request = $event->getRequest();
-    $response = $event->getResponse();
-    // Continue if the site is online and the response is not a redirection.
-    if ($request->attributes->get('_maintenance') != static::SITE_ONLINE && !($response instanceof RedirectResponse)) {
-      // Deliver the 503 page.
-      drupal_maintenance_theme();
-      $content = Xss::filterAdmin(String::format($this->config->get('system.maintenance')->get('message'), array(
-        '@site' => $this->config->get('system.site')->get('name'),
-      )));
-      $content = DefaultHtmlPageRenderer::renderPage($content, t('Site under maintenance'));
-      $response = new Response('Service unavailable', 503);
-      $response->setContent($content);
-      $event->setResponse($response);
-    }
-
-    $can_access_maintenance = $this->account->hasPermission('access site in maintenance mode');
-    $is_maintenance = $this->state->get('system.maintenance_mode');
-    // Ensure that the maintenance mode message is displayed only once
-    // (allowing for page redirects) and specifically suppress its display on
-    // the maintenance mode settings page.
-    $is_maintenance_route = $request->attributes->get(RouteObjectInterface::ROUTE_NAME) == 'system.site_maintenance_mode';
-    if ($is_maintenance && $can_access_maintenance && !$is_maintenance_route) {
-      if ($this->account->hasPermission('administer site configuration')) {
-        $this->drupalSetMessage($this->t('Operating in maintenance mode. <a href="@url">Go online.</a>', array('@url' => $this->urlGenerator->generate('system.site_maintenance_mode'))), 'status', FALSE);
+    if ($this->statusNegotiator->getStatus() != StatusNegotiatorInterface::SITE_ONLINE) {
+      $route_match = RouteMatch::createFromRequest($event->getRequest());
+      if (!$this->statusNegotiator->exempt($route_match, $this->account)) {
+        // Deliver the 503 page if the site is in maintenance mode and the
+        // logged in user is not allowed to bypass it.
+        drupal_maintenance_theme();
+        $content = Xss::filterAdmin(String::format($this->config->get('system.maintenance')->get('message'), array(
+          '@site' => $this->config->get('system.site')->get('name'),
+        )));
+        $content = DefaultHtmlPageRenderer::renderPage($content, t('Site under maintenance'));
+        $response = new Response('Service unavailable', 503);
+        $response->setContent($content);
+        $event->setResponse($response);
       }
       else {
-        $this->drupalSetMessage($this->t('Operating in maintenance mode.'), 'status', FALSE);
-      }
-    }
-  }
-
-  /**
-   * Checks whether the site is in maintenance mode.
-   *
-   * @return bool
-   *   FALSE if the site is not in maintenance mode
-   */
-  protected function isSiteInMaintenance() {
-    // Check if site is in maintenance mode.
-    if ($this->state->get('system.maintenance_mode')) {
-      if (!$this->account->hasPermission('access site in maintenance mode')) {
-        return TRUE;
+        // Display a message if the logged in user has access to the site in
+        // maintenance mode. However, suppress it on the maintenance mode
+        // setting spage.
+        if ($route_match->getRouteName() != 'system.site_maintenance_mode') {
+          if ($this->account->hasPermission('administer site configuration')) {
+            $this->drupalSetMessage($this->t('Operating in maintenance mode. <a href="@url">Go online.</a>', array('@url' => $this->urlGenerator->generate('system.site_maintenance_mode'))), 'status', FALSE);
+          }
+          else {
+            $this->drupalSetMessage($this->t('Operating in maintenance mode.'), 'status', FALSE);
+          }
+        }
       }
     }
-    return FALSE;
   }
 
   /**
@@ -177,10 +128,7 @@ protected function drupalSetMessage($message = NULL, $type = 'status', $repeat =
   /**
    * {@inheritdoc}
    */
-  static function getSubscribedEvents() {
-    // In order to change the maintenance status an event subscriber with a
-    // priority between 30 and 40 should be added.
-    $events[KernelEvents::REQUEST][] = array('onKernelRequestDetermineSiteStatus', 40);
+  public static function getSubscribedEvents() {
     $events[KernelEvents::REQUEST][] = array('onKernelRequestMaintenance', 30);
     return $events;
   }
diff --git a/core/lib/Drupal/Core/Site/MaintenanceExemptionInterface.php b/core/lib/Drupal/Core/Site/MaintenanceExemptionInterface.php
new file mode 100644
index 0000000..01a487f
--- /dev/null
+++ b/core/lib/Drupal/Core/Site/MaintenanceExemptionInterface.php
@@ -0,0 +1,30 @@
+<?php
+/**
+ * @file
+ * Contains \Drupal\Core\Site\MaintenanceExemptionInterface.
+ */
+
+namespace Drupal\Core\Site;
+
+use Drupal\Core\Session\AccountInterface;
+use Drupal\Core\Routing\RouteMatchInterface;
+
+/**
+ * Provides an interface for maintenance mode exemption rule implementations.
+ */
+interface MaintenanceExemptionInterface {
+
+  /**
+   * Returns TRUE if the given account should be exempted from maintenance mode.
+   *
+   * @param \Drupal\Core\Routing\RouteMatchInterface $route_match
+   *   The current route match.
+   * @param \Drupal\Core\Session\AccountInterface $account
+   *   The logged in user.
+   *
+   * @return bool
+   *   TRUE if the user should be exempted from maintenance mode.
+   */
+  public function exempt(RouteMatchInterface $route_match, AccountInterface $account);
+
+}
diff --git a/core/lib/Drupal/Core/Site/StatusNegotiator.php b/core/lib/Drupal/Core/Site/StatusNegotiator.php
new file mode 100644
index 0000000..4e5be60
--- /dev/null
+++ b/core/lib/Drupal/Core/Site/StatusNegotiator.php
@@ -0,0 +1,74 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Site\StatusNegotiator;
+ */
+
+namespace Drupal\Core\Site;
+
+use Drupal\Core\Routing\RouteMatchInterface;
+use Drupal\Core\Session\AccountInterface;
+use Drupal\Core\State\StateInterface;
+
+/**
+ * Provides the default implementation of the site status negotiator.
+ */
+class StatusNegotiator implements StatusNegotiatorInterface {
+
+  /**
+   * The state.
+   *
+   * @var \Drupal\Core\State\StateInterface
+   */
+  protected $state;
+
+  /**
+   * A list of maintenance mode exemption handlers.
+   *
+   * @var \Drupal\Core\Site\MaintenanceExemptionInterface[]
+   */
+  protected $exemptionHandlers;
+
+  /**
+   * Constructs a new maintenance status negotiator.
+   *
+   * @param \Drupal\Core\State\StateInterface $state
+   *   The state.
+   */
+  public function __construct(StateInterface $state) {
+    $this->state = $state;
+    $this->exemptionHandlers = array();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getStatus() {
+    return $this->state->get('system.maintenance_mode') ? StatusNegotiatorInterface::SITE_OFFLINE : StatusNegotiatorInterface::SITE_ONLINE;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function exempt(RouteMatchInterface $route_match, AccountInterface $account) {
+    foreach ($this->exemptionHandlers as $handler) {
+      if ($handler->exempt($route_match, $account)) {
+        return TRUE;
+      }
+    }
+
+    return FALSE;
+  }
+
+  /**
+   * Add an exemption handler.
+   *
+   * @param \Drupal\Core\Site\MaintenanceExemptionInterface $handler
+   *   A maintenance exemption handler.
+   */
+  public function addExemption(MaintenanceExemptionInterface $handler) {
+    $this->exemptionHandlers[] = $handler;
+  }
+
+}
diff --git a/core/lib/Drupal/Core/Site/StatusNegotiatorInterface.php b/core/lib/Drupal/Core/Site/StatusNegotiatorInterface.php
new file mode 100644
index 0000000..0eabb49
--- /dev/null
+++ b/core/lib/Drupal/Core/Site/StatusNegotiatorInterface.php
@@ -0,0 +1,45 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Site\StatusNegotiatorInterface;
+ */
+
+namespace Drupal\Core\Site;
+
+use Drupal\Core\State\StateInterface;
+
+/**
+ * Provides the default implementation of the site status negotiator.
+ */
+interface StatusNegotiatorInterface extends MaintenanceExemptionInterface {
+
+  /**
+   * @defgroup menu_status_codes Menu status codes
+   * @{
+   * Status codes to be used to check the maintenance code.
+   */
+
+  /**
+   * Internal menu status code -- Menu item inaccessible because site is offline.
+   */
+  const SITE_OFFLINE = 4;
+
+  /**
+   * Internal menu status code -- Everything is working fine.
+   */
+  const SITE_ONLINE = 5;
+
+  /**
+   * @} End of "defgroup menu_status_codes".
+   */
+
+  /**
+   * Returns whether the site is in maintenance mode.
+   *
+   * @return int
+   *   Either static::SITE_OFFLINE or static::SITE_ONLINE.
+   */
+  public function getStatus();
+
+}
diff --git a/core/modules/system/src/Site/MaintenanceExemption.php b/core/modules/system/src/Site/MaintenanceExemption.php
new file mode 100644
index 0000000..22036f5
--- /dev/null
+++ b/core/modules/system/src/Site/MaintenanceExemption.php
@@ -0,0 +1,28 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\system\Site\MaintenanceExemption.
+ */
+
+namespace Drupal\system\Site;
+
+use Drupal\Core\Routing\RouteMatchInterface;
+use Drupal\Core\Session\AccountInterface;
+use Drupal\Core\Site\MaintenanceExemptionInterface;
+
+/**
+ * Exempts administrators from the maintenance mode.
+ */
+class MaintenanceExemption implements MaintenanceExemptionInterface {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function exempt(RouteMatchInterface $route_match, AccountInterface $account) {
+    if ($account->hasPermission('access site in maintenance mode')) {
+      return TRUE;
+    }
+  }
+
+}
diff --git a/core/modules/system/system.services.yml b/core/modules/system/system.services.yml
index 2b7046c..9913425 100644
--- a/core/modules/system/system.services.yml
+++ b/core/modules/system/system.services.yml
@@ -33,3 +33,7 @@ services:
     arguments: ['@cron', '@config.factory', '@state']
     tags:
       - { name: event_subscriber }
+  system.maintenance_mode_exemption:
+    class: Drupal\system\Site\MaintenanceExemption
+    tags:
+      - { name: maintenance_mode_exemption }
diff --git a/core/modules/system/tests/modules/menu_test/menu_test.services.yml b/core/modules/system/tests/modules/menu_test/menu_test.services.yml
index b52f8cf..951274f 100644
--- a/core/modules/system/tests/modules/menu_test/menu_test.services.yml
+++ b/core/modules/system/tests/modules/menu_test/menu_test.services.yml
@@ -1,8 +1,8 @@
 services:
-  menu_test_maintenance_mode_subscriber:
-    class: Drupal\menu_test\EventSubscriber\MaintenanceModeSubscriber
+  menu_test_maintenance_mode_exemption:
+    class: Drupal\menu_test\Site\MaintenanceExemption
     tags:
-      - { name: event_subscriber }
+      - { name: maintenance_mode_exemption }
 
   theme.negotiator.test_theme:
     class: Drupal\menu_test\Theme\TestThemeNegotiator
diff --git a/core/modules/system/tests/modules/menu_test/src/EventSubscriber/MaintenanceModeSubscriber.php b/core/modules/system/tests/modules/menu_test/src/EventSubscriber/MaintenanceModeSubscriber.php
deleted file mode 100644
index 0b6ae61..0000000
--- a/core/modules/system/tests/modules/menu_test/src/EventSubscriber/MaintenanceModeSubscriber.php
+++ /dev/null
@@ -1,43 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\menu_test\EventSubscriber\MaintenanceModeSubscriber.
- */
-
-namespace Drupal\menu_test\EventSubscriber;
-
-use Symfony\Component\EventDispatcher\EventSubscriberInterface;
-use Symfony\Component\HttpKernel\Event\GetResponseEvent;
-use Symfony\Component\HttpKernel\KernelEvents;
-use Drupal\Core\EventSubscriber\MaintenanceModeSubscriber as CoreMaintenanceModeSubscriber;
-
-
-/**
- * Maintenance mode subscriber to set site online on a test.
- */
-class MaintenanceModeSubscriber implements EventSubscriberInterface {
-
-  /**
-   * Set the page online if called from a certain path.
-   *
-   * @param \Symfony\Component\HttpKernel\Event\GetResponseEvent $event
-   *   The event to process.
-   */
-  public function onKernelRequestMaintenance(GetResponseEvent $event) {
-    $request = $event->getRequest();
-    // Allow access to menu_login_callback even if in maintenance mode.
-    if ($request->attributes->get('_maintenance') == CoreMaintenanceModeSubscriber::SITE_OFFLINE && $request->attributes->get('_system_path') == 'menu_login_callback') {
-      $request->attributes->set('_maintenance', CoreMaintenanceModeSubscriber::SITE_ONLINE);
-    }
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public static function getSubscribedEvents() {
-    $events[KernelEvents::REQUEST][] = array('onKernelRequestMaintenance', 35);
-    return $events;
-  }
-
-}
diff --git a/core/modules/system/tests/modules/menu_test/src/Site/MaintenanceExemption.php b/core/modules/system/tests/modules/menu_test/src/Site/MaintenanceExemption.php
new file mode 100644
index 0000000..750a83a
--- /dev/null
+++ b/core/modules/system/tests/modules/menu_test/src/Site/MaintenanceExemption.php
@@ -0,0 +1,29 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\menu_test\Site\MaintenanceExemption.
+ */
+
+namespace Drupal\menu_test\Site;
+
+use Drupal\Core\Routing\RouteMatchInterface;
+use Drupal\Core\Session\AccountInterface;
+use Drupal\Core\Site\MaintenanceExemptionInterface;
+
+
+/**
+ * Maintenance mode subscriber to set site online on a test.
+ */
+class MaintenanceExemption implements MaintenanceExemptionInterface {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function exempt(RouteMatchInterface $route_match, AccountInterface $account) {
+    if ($route_match->getRouteName() == 'menu_test.login_callback') {
+      return TRUE;
+    }
+  }
+
+}
diff --git a/core/modules/user/src/EventSubscriber/MaintenanceModeSubscriber.php b/core/modules/user/src/EventSubscriber/MaintenanceModeSubscriber.php
index 1e8d114..73d5c9e 100644
--- a/core/modules/user/src/EventSubscriber/MaintenanceModeSubscriber.php
+++ b/core/modules/user/src/EventSubscriber/MaintenanceModeSubscriber.php
@@ -7,11 +7,13 @@
 
 namespace Drupal\user\EventSubscriber;
 
+use Drupal\Core\Routing\RouteMatch;
+use Drupal\Core\Session\AccountInterface;
+use Drupal\Core\Site\StatusNegotiatorInterface;
 use Symfony\Component\EventDispatcher\EventSubscriberInterface;
 use Symfony\Component\HttpFoundation\RedirectResponse;
 use Symfony\Component\HttpKernel\Event\GetResponseEvent;
 use Symfony\Component\HttpKernel\KernelEvents;
-use Drupal\Core\EventSubscriber\MaintenanceModeSubscriber as CoreMaintenanceModeSubscriber;
 
 /**
  * Maintenance mode subscriber to logout users.
@@ -19,46 +21,59 @@
 class MaintenanceModeSubscriber implements EventSubscriberInterface {
 
   /**
+   * The maintenance mode negotiator.
+   *
+   * @var \Drupal\Core\Site\StatusNegotiator
+   */
+  protected $statusNegotiator;
+
+  /**
+   * The current account.
+   *
+   * @var \Drupal\Core\Session\AccountInterface
+   */
+  protected $account;
+
+  /**
+   * Constructs a new MaintenanceModeSubscriber.
+   *
+   * @param \Drupal\Core\Site\StatusNegotiatorInterface $status_negotiator
+   *   The site status negotiator.
+   * @param \Drupal\Core\Session\AccountInterface $account
+   *   The current user.
+   */
+  public function __construct(StatusNegotiatorInterface $status_negotiator, AccountInterface $account) {
+    $this->statusNegotiator = $status_negotiator;
+    $this->account = $account;
+  }
+
+  /**
    * Determine whether the page is configured to be offline.
    *
    * @param \Symfony\Component\HttpKernel\Event\GetResponseEvent $event
    *   The event to process.
    */
   public function onKernelRequestMaintenance(GetResponseEvent $event) {
-    $user = \Drupal::currentUser();
     $request = $event->getRequest();
-    $site_status = $request->attributes->get('_maintenance');
+    $site_status = $this->statusNegotiator->getStatus();
     $path = $request->attributes->get('_system_path');
-    if ($site_status == CoreMaintenanceModeSubscriber::SITE_OFFLINE) {
+    if ($site_status == StatusNegotiatorInterface::SITE_OFFLINE) {
+      $route_match = RouteMatch::createFromRequest($request);
       // If the site is offline, log out unprivileged users.
-      if ($user->isAuthenticated() && !$user->hasPermission('access site in maintenance mode')) {
+      if ($this->account->isAuthenticated() && !$this->statusNegotiator->exempt($route_match, $this->account)) {
         user_logout();
         // Redirect to homepage.
         $event->setResponse(new RedirectResponse(url('<front>', array('absolute' => TRUE))));
         return;
       }
 
-      if ($user->isAnonymous()) {
-        switch ($path) {
-          case 'user':
-            // Forward anonymous user to login page.
-            $event->setResponse(new RedirectResponse(url('user/login', array('absolute' => TRUE))));
-            return;
-          case 'user/login':
-          case 'user/password':
-            // Disable offline mode.
-            $request->attributes->set('_maintenance', CoreMaintenanceModeSubscriber::SITE_ONLINE);
-            break;
-          default:
-            if (strpos($path, 'user/reset/') === 0) {
-              // Disable offline mode.
-              $request->attributes->set('_maintenance', CoreMaintenanceModeSubscriber::SITE_ONLINE);
-            }
-            break;
-        }
+      if ($this->account->isAnonymous() && $path == 'user') {
+        // Forward anonymous user to login page.
+        $event->setResponse(new RedirectResponse(url('user/login', array('absolute' => TRUE))));
+        return;
       }
     }
-    if ($user->isAuthenticated()) {
+    if ($this->account->isAuthenticated()) {
       if ($path == 'user/login') {
         // If user is logged in, redirect to 'user' instead of giving 403.
         $event->setResponse(new RedirectResponse(url('user', array('absolute' => TRUE))));
@@ -66,7 +81,7 @@ public function onKernelRequestMaintenance(GetResponseEvent $event) {
       }
       if ($path == 'user/register') {
         // Authenticated user should be redirected to user edit page.
-        $event->setResponse(new RedirectResponse(url('user/' . $user->id() . '/edit', array('absolute' => TRUE))));
+        $event->setResponse(new RedirectResponse(url('user/' . $this->account->id() . '/edit', array('absolute' => TRUE))));
         return;
       }
     }
diff --git a/core/modules/user/src/Site/MaintenanceExemption.php b/core/modules/user/src/Site/MaintenanceExemption.php
new file mode 100644
index 0000000..c914c4d
--- /dev/null
+++ b/core/modules/user/src/Site/MaintenanceExemption.php
@@ -0,0 +1,29 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\user\Site\MaintenanceExemption.
+ */
+
+namespace Drupal\user\Site;
+
+use Drupal\Core\Routing\RouteMatchInterface;
+use Drupal\Core\Session\AccountInterface;
+use Drupal\Core\Site\MaintenanceExemptionInterface;
+
+/**
+ * Exempts login and password-retrieval form from the maintenance mode.
+ */
+class MaintenanceExemption implements MaintenanceExemptionInterface {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function exempt(RouteMatchInterface $route_match, AccountInterface $account) {
+    $route_name = $route_match->getRouteName();
+    if ($route_name == 'user.login' || $route_name == 'user.pass' || $route_name == 'user.reset') {
+      return TRUE;
+    }
+  }
+
+}
diff --git a/core/modules/user/user.services.yml b/core/modules/user/user.services.yml
index 1e8f9b3..74b68df 100644
--- a/core/modules/user/user.services.yml
+++ b/core/modules/user/user.services.yml
@@ -38,6 +38,7 @@ services:
     arguments: ['@database', '@config.factory', '@entity.manager', '@entity.query']
   user_maintenance_mode_subscriber:
     class: Drupal\user\EventSubscriber\MaintenanceModeSubscriber
+    arguments: ['@site_status_negotiator', '@current_user']
     tags:
       - { name: event_subscriber }
   theme.negotiator.admin_theme:
@@ -54,3 +55,7 @@ services:
   user.tempstore:
     class: Drupal\user\TempStoreFactory
     arguments: ['@serialization.phpserialize', '@database', '@lock']
+  user.maintenance_mode_exemption:
+    class: Drupal\user\Site\MaintenanceExemption
+    tags:
+      - { name: maintenance_mode_exemption }
