diff --git a/core/core.services.yml b/core/core.services.yml
index 9ca753e6a4..f835de57b3 100644
--- a/core/core.services.yml
+++ b/core/core.services.yml
@@ -1221,7 +1221,7 @@ services:
     class: Drupal\Core\EventSubscriber\AnonymousUserResponseSubscriber
     tags:
       - { name: event_subscriber }
-    arguments: ['@current_user']
+    arguments: ['@current_user', '@messenger']
   ajax_response.attachments_processor:
     class: Drupal\Core\Ajax\AjaxResponseAttachmentsProcessor
     tags:
diff --git a/core/lib/Drupal/Core/EventSubscriber/AnonymousUserResponseSubscriber.php b/core/lib/Drupal/Core/EventSubscriber/AnonymousUserResponseSubscriber.php
index 6d143b2fbd..89fad6bf6f 100644
--- a/core/lib/Drupal/Core/EventSubscriber/AnonymousUserResponseSubscriber.php
+++ b/core/lib/Drupal/Core/EventSubscriber/AnonymousUserResponseSubscriber.php
@@ -4,8 +4,11 @@
 
 use Drupal\Core\Cache\CacheableMetadata;
 use Drupal\Core\Cache\CacheableResponseInterface;
+use Drupal\Core\Messenger\MessengerInterface;
 use Drupal\Core\Session\AccountInterface;
+use Drupal\Core\StringTranslation\StringTranslationTrait;
 use Symfony\Component\HttpKernel\Event\FilterResponseEvent;
+use Symfony\Component\HttpKernel\Event\GetResponseEvent;
 use Symfony\Component\HttpKernel\KernelEvents;
 use Symfony\Component\EventDispatcher\EventSubscriberInterface;
 
@@ -14,6 +17,8 @@
  */
 class AnonymousUserResponseSubscriber implements EventSubscriberInterface {
 
+  use StringTranslationTrait;
+
   /**
    * The current user.
    *
@@ -22,13 +27,21 @@ class AnonymousUserResponseSubscriber implements EventSubscriberInterface {
   protected $currentUser;
 
   /**
+   * The messenger service.
+   *
+   * @var \Drupal\Core\Messenger\MessengerInterface
+   */
+  protected $messenger;
+
+  /**
    * Constructs an AnonymousUserResponseSubscriber object.
    *
    * @param \Drupal\Core\Session\AccountInterface $current_user
    *   The current user.
    */
-  public function __construct(AccountInterface $current_user) {
+  public function __construct(AccountInterface $current_user, MessengerInterface $messenger) {
     $this->currentUser = $current_user;
+    $this->messenger = $messenger;
   }
 
   /**
@@ -66,6 +79,25 @@ public function onRespond(FilterResponseEvent $event) {
   }
 
   /**
+   * Check if the user has cookies enabled.
+   *
+   * If the user was redirected to this page on an attempted login but the
+   * login didn't succeed, warn them about missing cookies.
+   *
+   * @see \Drupal\user\Form\UserLoginForm::submitForm()
+   * @param \Symfony\Component\HttpKernel\Event\GetResponseEvent $event
+   *   The event to process.
+   */
+  public function onKernelCheckUserCookies(GetResponseEvent $event) {
+    /** @var \Symfony\Component\HttpFoundation\Request $request */
+    $request = $event->getRequest();
+    if ($request->query->get('state') == 'loggedin' && $this->currentUser->isAnonymous()) {
+      $domain = ini_get('session.cookie_domain') ? ltrim(ini_get('session.cookie_domain'), '.') : $request->server->get('HTTP_HOST');
+      $this->messenger->addMessage($this->t('To log in to this site, your browser must accept cookies from the domain %domain.', ['%domain' => $domain]), 'error');
+    }
+  }
+
+  /**
    * Registers the methods in this class that should be listeners.
    *
    * @return array
@@ -76,6 +108,7 @@ public static function getSubscribedEvents() {
     // event subscribers that add the associated cacheability metadata (which
     // have priority 10). This one is conditional, so must run after those.
     $events[KernelEvents::RESPONSE][] = ['onRespond', 5];
+    $events[KernelEvents::REQUEST][] = ['onKernelCheckUserCookies'];
     return $events;
   }
 
diff --git a/core/modules/big_pipe/tests/src/Functional/BigPipeTest.php b/core/modules/big_pipe/tests/src/Functional/BigPipeTest.php
index 17ae4f65f8..d3429da763 100644
--- a/core/modules/big_pipe/tests/src/Functional/BigPipeTest.php
+++ b/core/modules/big_pipe/tests/src/Functional/BigPipeTest.php
@@ -10,6 +10,7 @@
 use Drupal\Component\Utility\Html;
 use Drupal\Core\Logger\RfcLogLevel;
 use Drupal\Core\Url;
+use Drupal\Component\Utility\UrlHelper;
 use Drupal\Tests\BrowserTestBase;
 
 /**
@@ -88,7 +89,7 @@ public function testNoJsDetection() {
     $this->drupalLogin($this->rootUser);
     $this->assertSessionCookieExists(TRUE);
     $this->assertBigPipeNoJsCookieExists(FALSE);
-    $this->assertRaw('<noscript><meta http-equiv="Refresh" content="0; URL=' . base_path() . 'big_pipe/no-js?destination=' . base_path() . 'user/1" />' . "\n" . '</noscript>');
+    $this->assertRaw('<noscript><meta http-equiv="Refresh" content="0; URL=' . base_path() . 'big_pipe/no-js?destination=' . UrlHelper::encodePath(base_path() . 'user/1?state=loggedin') . '" />' . "\n" . '</noscript>');
     $this->assertNoRaw($no_js_to_js_markup);
     $this->assertBigPipeNoJsMetaRefreshRedirect();
     $this->assertBigPipeNoJsCookieExists(TRUE);
diff --git a/core/modules/system/tests/src/Functional/Session/SessionHttpsTest.php b/core/modules/system/tests/src/Functional/Session/SessionHttpsTest.php
index f746f9dbb9..f5785cc475 100644
--- a/core/modules/system/tests/src/Functional/Session/SessionHttpsTest.php
+++ b/core/modules/system/tests/src/Functional/Session/SessionHttpsTest.php
@@ -154,7 +154,12 @@ protected function loginHttp(AccountInterface $account) {
 
     // Follow the location header.
     $path = $this->getPathFromLocationHeader($response, FALSE);
-    $this->drupalGet($this->httpUrl($path));
+    $parsed_path = parse_url($path);
+    $query = [];
+    if (isset($parsed_path['query'])) {
+      parse_str($parsed_path['query'], $query);
+    }
+    $this->drupalGet($this->httpUrl($parsed_path['path']), ['query' => $query]);
     $this->assertResponse(200);
   }
 
@@ -200,7 +205,12 @@ protected function loginHttps(AccountInterface $account) {
 
     // Follow the location header.
     $path = $this->getPathFromLocationHeader($response, TRUE);
-    $this->drupalGet($this->httpsUrl($path));
+    $parsed_path = parse_url($path);
+    $query = [];
+    if (isset($parsed_path['query'])) {
+      parse_str($parsed_path['query'], $query);
+    }
+    $this->drupalGet($this->httpsUrl($parsed_path['path']), ['query' => $query]);
     $this->assertResponse(200);
   }
 
diff --git a/core/modules/user/src/Form/UserLoginForm.php b/core/modules/user/src/Form/UserLoginForm.php
index ac5324abe6..135ecf6913 100644
--- a/core/modules/user/src/Form/UserLoginForm.php
+++ b/core/modules/user/src/Form/UserLoginForm.php
@@ -136,7 +136,8 @@ public function submitForm(array &$form, FormStateInterface $form_state) {
     if (!$this->getRequest()->request->has('destination')) {
       $form_state->setRedirect(
         'entity.user.canonical',
-        ['user' => $account->id()]
+        ['user' => $account->id()],
+        ['query' => ['state' => 'loggedin']]
       );
     }
     else {
diff --git a/core/modules/user/src/Plugin/Block/UserLoginBlock.php b/core/modules/user/src/Plugin/Block/UserLoginBlock.php
index c76e9b6189..eeea5ec784 100644
--- a/core/modules/user/src/Plugin/Block/UserLoginBlock.php
+++ b/core/modules/user/src/Plugin/Block/UserLoginBlock.php
@@ -2,6 +2,7 @@
 
 namespace Drupal\user\Plugin\Block;
 
+use Drupal\Component\Utility\UrlHelper;
 use Drupal\Core\Access\AccessResult;
 use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
 use Drupal\Core\Routing\RedirectDestinationTrait;
@@ -152,9 +153,20 @@ public function build() {
    * @see \Drupal\Core\Form\FormBuilder::renderPlaceholderFormAction()
    */
   public static function renderPlaceholderFormAction() {
+    // Set the form action so that the user will be redirected to the current
+    // destination after logging in. Also append a query parameter to the
+    // destination in  so we can check later if the login was successful; see
+    // user_init().
+    $destination = \Drupal::destination()->getAsArray();
+    $options = UrlHelper::parse($destination['destination']);
+    $options['query']['state'] = 'loggedin';
+    $destination['destination'] = $options['path'] . '?' . UrlHelper::buildQuery($options['query']);
     return [
       '#type' => 'markup',
-      '#markup' => Url::fromRoute('<current>', [], ['query' => \Drupal::destination()->getAsArray(), 'external' => FALSE])->toString(),
+      '#markup' => Url::fromRoute('<current>', [], [
+        'query' => $destination,
+        'external' => FALSE,
+      ])->toString(),
       '#cache' => ['contexts' => ['url.path', 'url.query_args']],
     ];
   }
diff --git a/core/modules/user/tests/src/Functional/UserBlocksTest.php b/core/modules/user/tests/src/Functional/UserBlocksTest.php
index 6c56ff1f89..bd7f187685 100644
--- a/core/modules/user/tests/src/Functional/UserBlocksTest.php
+++ b/core/modules/user/tests/src/Functional/UserBlocksTest.php
@@ -4,6 +4,7 @@
 
 use Drupal\Core\Database\Database;
 use Drupal\dynamic_page_cache\EventSubscriber\DynamicPageCacheSubscriber;
+use Drupal\Core\Url;
 use Drupal\Tests\BrowserTestBase;
 
 /**
@@ -75,7 +76,8 @@ public function testUserLoginBlock() {
     $this->assertNoText(t('User login'), 'Logged in.');
 
     // Check that we are still on the same page.
-    $this->assertUrl(\Drupal::url('user.admin_permissions', [], ['absolute' => TRUE]), [], 'Still on the same page after login for access denied page');
+    $url = Url::fromRoute('user.admin_permissions', [], ['absolute' => TRUE, 'query' => ['state' => 'loggedin']]);
+    $this->assertUrl($url, [], 'Still on the same page after login for access denied page');
 
     // Now, log out and repeat with a non-403 page.
     $this->drupalLogout();
