diff --git a/core/core.services.yml b/core/core.services.yml
index f715064..9bfc560 100644
--- a/core/core.services.yml
+++ b/core/core.services.yml
@@ -589,9 +589,12 @@ services:
     tags:
       - { name: access_check, applies_to: _csrf_token }
     arguments: ['@csrf_token']
+  site_status_negotiator:
+    class: Drupal\Core\Site\StatusNegotiator
+    arguments: ['@state', '@current_user']
   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..d9b5f1f 100644
--- a/core/lib/Drupal/Core/EventSubscriber/MaintenanceModeSubscriber.php
+++ b/core/lib/Drupal/Core/EventSubscriber/MaintenanceModeSubscriber.php
@@ -13,6 +13,7 @@
 use Drupal\Core\Page\DefaultHtmlPageRenderer;
 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;
@@ -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,19 +82,6 @@ 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
@@ -121,10 +89,9 @@ public function onKernelRequestDetermineSiteStatus(GetResponseEvent $event) {
    */
   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.
+    if ($this->statusNegotiator->getStatus($this->account) != StatusNegotiatorInterface::SITE_ONLINE) {
+      // 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'),
@@ -134,37 +101,20 @@ public function onKernelRequestMaintenance(GetResponseEvent $event) {
       $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);
-      }
-      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;
+    elseif ($this->statusNegotiator->getStatus() != StatusNegotiatorInterface::SITE_ONLINE) {
+      // 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.
+      $is_maintenance_route = $request->attributes->get(RouteObjectInterface::ROUTE_NAME) == 'system.site_maintenance_mode';
+      if (!$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);
+        }
+        else {
+          $this->drupalSetMessage($this->t('Operating in maintenance mode.'), 'status', FALSE);
+        }
       }
     }
-    return FALSE;
   }
 
   /**
@@ -177,10 +127,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/.StatusNegotiatorInterface.php.swo b/core/lib/Drupal/Core/Site/.StatusNegotiatorInterface.php.swo
new file mode 100644
index 0000000..883b4e0
Binary files /dev/null and b/core/lib/Drupal/Core/Site/.StatusNegotiatorInterface.php.swo differ
diff --git a/core/lib/Drupal/Core/Site/StatusNegotiator.php b/core/lib/Drupal/Core/Site/StatusNegotiator.php
new file mode 100644
index 0000000..1fb3466
--- /dev/null
+++ b/core/lib/Drupal/Core/Site/StatusNegotiator.php
@@ -0,0 +1,62 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Site\StatusNegotiator;
+ */
+
+namespace Drupal\Core\Site;
+
+use Drupal\Core\State\StateInterface;
+use Drupal\Core\Session\AccountInterface;
+
+/**
+ * Provides the default implementation of the site status negotiator.
+ */
+class StatusNegotiator implements StatusNegotiatorInterface {
+
+  /**
+   * The state.
+   *
+   * @var \Drupal\Core\State\StateInterface
+   */
+  protected $state;
+
+  /**
+   * The maintenance status.
+   */
+  protected $status;
+
+  /**
+   * Constructs a new maintenance status negotiator.
+   *
+   * @param \Drupal\Core\State\StateInterface $state
+   *   The state.
+   */
+  public function __construct(StateInterface $state) {
+    $this->state = $state;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getStatus(AccountInterface $account = NULL) {
+    if (!isset($this->status)) {
+      $this->status = $this->state->get('system.maintenance_mode') ? StatusNegotiatorInterface::SITE_OFFLINE : StatusNegotiatorInterface::SITE_ONLINE;
+    }
+
+    if (isset($account) && $account->hasPermission('access site in maintenance mode')) {
+      return StatusNegotiatorInterface::SITE_ONLINE;
+    }
+
+    return $this->status;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function overrideStatus($status = NULL) {
+    $this->status = $status;
+  }
+
+}
diff --git a/core/lib/Drupal/Core/Site/StatusNegotiatorInterface.php b/core/lib/Drupal/Core/Site/StatusNegotiatorInterface.php
new file mode 100644
index 0000000..153380f
--- /dev/null
+++ b/core/lib/Drupal/Core/Site/StatusNegotiatorInterface.php
@@ -0,0 +1,59 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Site\StatusNegotiatorInterface;
+ */
+
+namespace Drupal\Core\Site;
+
+use Drupal\Core\State\StateInterface;
+use Drupal\Core\Session\AccountInterface;
+
+/**
+ * Provides the default implementation of the site status negotiator.
+ */
+interface StatusNegotiatorInterface {
+
+  /**
+   * @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.
+   *
+   * @param \Drupal\Core\Session\AccountInterface $account
+   *   (optional) An account to use when checking whether the site should be
+   *   displayed in maintenance mode. If omitted, the site status is returned.
+   *
+   * @return int
+   *   Either static::SITE_OFFLINE or static::SITE_ONLINE.
+   */
+  public function getStatus(AccountInterface $account = NULL);
+
+  /**
+   * Overrides the site status for the current request.
+   *
+   * @param int $status
+   *   (optional) Either static::SITE_OFFLINE or static::SITE_ONLINE. If
+   *   omitted, the overridden status is cleared.
+   */
+  public function overrideStatus($status = NULL);
+
+}
diff --git a/core/modules/system/src/Tests/Menu/MenuRouterTest.php b/core/modules/system/src/Tests/Menu/MenuRouterTest.php
index 4383658..202c662 100644
--- a/core/modules/system/src/Tests/Menu/MenuRouterTest.php
+++ b/core/modules/system/src/Tests/Menu/MenuRouterTest.php
@@ -342,8 +342,6 @@ public function testMaintenanceModeLoginPaths() {
     $offline_message = t('@site is currently under maintenance. We should be back shortly. Thank you for your patience.', array('@site' => \Drupal::config('system.site')->get('name')));
     $this->drupalGet('test-page');
     $this->assertText($offline_message);
-    $this->drupalGet('menu_login_callback');
-    $this->assertText('This is TestControllers::testLogin.', 'Maintenance mode can be bypassed using an event subscriber.');
 
     $this->container->get('state')->set('system.maintenance_mode', FALSE);
   }
diff --git a/core/modules/system/tests/modules/menu_test/menu_test.routing.yml b/core/modules/system/tests/modules/menu_test/menu_test.routing.yml
index 6c3c106..724e58f 100644
--- a/core/modules/system/tests/modules/menu_test/menu_test.routing.yml
+++ b/core/modules/system/tests/modules/menu_test/menu_test.routing.yml
@@ -14,13 +14,6 @@ menu_test.menu_callback_title:
   requirements:
     _access: 'TRUE'
 
-menu_test.login_callback:
-  path: '/menu_login_callback'
-  defaults:
-    _content: '\Drupal\menu_test\TestControllers::testLogin'
-  requirements:
-    _access: 'TRUE'
-
 menu_test.callback_description:
   path: '/menu_callback_description'
   defaults:
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..8841320 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,9 +1,4 @@
 services:
-  menu_test_maintenance_mode_subscriber:
-    class: Drupal\menu_test\EventSubscriber\MaintenanceModeSubscriber
-    tags:
-      - { name: event_subscriber }
-
   theme.negotiator.test_theme:
     class: Drupal\menu_test\Theme\TestThemeNegotiator
     tags:
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/TestControllers.php b/core/modules/system/tests/modules/menu_test/src/TestControllers.php
index 608e0c7..df3f090 100644
--- a/core/modules/system/tests/modules/menu_test/src/TestControllers.php
+++ b/core/modules/system/tests/modules/menu_test/src/TestControllers.php
@@ -16,13 +16,6 @@
 class TestControllers {
 
   /**
-   * Returns page to be used as a login path.
-   */
-  public function testLogin() {
-    return 'This is TestControllers::testLogin.';
-  }
-
-  /**
    * Prints out test data.
    */
   public function test1() {
diff --git a/core/modules/user/src/EventSubscriber/MaintenanceModeSubscriber.php b/core/modules/user/src/EventSubscriber/MaintenanceModeSubscriber.php
index 1e8d114..2bcc631 100644
--- a/core/modules/user/src/EventSubscriber/MaintenanceModeSubscriber.php
+++ b/core/modules/user/src/EventSubscriber/MaintenanceModeSubscriber.php
@@ -7,11 +7,12 @@
 
 namespace Drupal\user\EventSubscriber;
 
+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,26 +20,52 @@
 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) {
       // If the site is offline, log out unprivileged users.
-      if ($user->isAuthenticated() && !$user->hasPermission('access site in maintenance mode')) {
+      if ($this->account->isAuthenticated() && !$this->account->hasPermission('access site in maintenance mode')) {
         user_logout();
         // Redirect to homepage.
         $event->setResponse(new RedirectResponse(url('<front>', array('absolute' => TRUE))));
         return;
       }
 
-      if ($user->isAnonymous()) {
+      if ($this->account->isAnonymous()) {
         switch ($path) {
           case 'user':
             // Forward anonymous user to login page.
@@ -47,18 +74,18 @@ public function onKernelRequestMaintenance(GetResponseEvent $event) {
           case 'user/login':
           case 'user/password':
             // Disable offline mode.
-            $request->attributes->set('_maintenance', CoreMaintenanceModeSubscriber::SITE_ONLINE);
+            $this->statusNegotiator->overrideStatus(StatusNegotiatorInterface::SITE_ONLINE);
             break;
           default:
             if (strpos($path, 'user/reset/') === 0) {
               // Disable offline mode.
-              $request->attributes->set('_maintenance', CoreMaintenanceModeSubscriber::SITE_ONLINE);
+              $this->statusNegotiator->overrideStatus(StatusNegotiatorInterface::SITE_ONLINE);
             }
             break;
         }
       }
     }
-    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 +93,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/user.services.yml b/core/modules/user/user.services.yml
index 1e8f9b3..3a3e3a8 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:
