diff --git a/core/modules/user/src/Controller/UserController.php b/core/modules/user/src/Controller/UserController.php
index 73c8fb3..f7e1fb7 100644
--- a/core/modules/user/src/Controller/UserController.php
+++ b/core/modules/user/src/Controller/UserController.php
@@ -8,11 +8,14 @@
 use Drupal\Core\Datetime\DateFormatterInterface;
 use Drupal\Core\Flood\FloodInterface;
 use Drupal\user\Form\UserPasswordResetForm;
+use Drupal\user\UserCrudEvent;
 use Drupal\user\UserDataInterface;
+use Drupal\user\UserEvents;
 use Drupal\user\UserInterface;
 use Drupal\user\UserStorageInterface;
 use Psr\Log\LoggerInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
+use Symfony\Component\EventDispatcher\EventDispatcherInterface;
 use Symfony\Component\HttpFoundation\Request;
 use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
 
@@ -50,11 +53,11 @@ class UserController extends ControllerBase {
   protected $logger;
 
   /**
-   * The flood service.
+   * The event dispatcher.
    *
-   * @var \Drupal\Core\Flood\FloodInterface
+   * @var \Symfony\Component\EventDispatcher\EventDispatcherInterface
    */
-  protected $flood;
+  protected $eventDispatcher;
 
   /**
    * Constructs a UserController object.
@@ -67,15 +70,15 @@ class UserController extends ControllerBase {
    *   The user data service.
    * @param \Psr\Log\LoggerInterface $logger
    *   A logger instance.
-   * @param \Drupal\Core\Flood\FloodInterface $flood
-   *   The flood service.
+   * @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $event_dispatcher
+   *   The event dispatcher.
    */
-  public function __construct(DateFormatterInterface $date_formatter, UserStorageInterface $user_storage, UserDataInterface $user_data, LoggerInterface $logger, FloodInterface $flood) {
+  public function __construct(DateFormatterInterface $date_formatter, UserStorageInterface $user_storage, UserDataInterface $user_data, LoggerInterface $logger, EventDispatcherInterface $event_dispatcher) {
     $this->dateFormatter = $date_formatter;
     $this->userStorage = $user_storage;
     $this->userData = $user_data;
     $this->logger = $logger;
-    $this->flood = $flood;
+    $this->eventDispatcher = $event_dispatcher;
   }
 
   /**
@@ -87,7 +90,7 @@ public static function create(ContainerInterface $container) {
       $container->get('entity.manager')->getStorage('user'),
       $container->get('user.data'),
       $container->get('logger.factory')->get('user'),
-      $container->get('flood')
+      $container->get('event_dispatcher')
     );
   }
 
@@ -236,18 +239,7 @@ public function resetPassLogin(Request $request, $uid, $timestamp, $hash) {
       return $this->redirect('user.pass');
     }
     elseif ($user->isAuthenticated() && ($timestamp >= $user->getLastLoginTime()) && ($timestamp <= $current) && Crypt::hashEquals($hash, user_pass_rehash($user, $timestamp))) {
-      $flood_config = $this->config('user.flood');
-      if ($flood_config->get('uid_only')) {
-        // Clear flood events based on the uid only if configured.
-        $identifier = $user->id();
-      }
-      else {
-        // The default identifier is a combination of uid and IP address.
-        $identifier = $user->id() . '-' . $request->getClientIP();
-      }
-      $this->flood->clear('user.failed_login_ip');
-      $this->flood->clear('user.failed_login_user', $identifier);
-
+      $this->eventDispatcher->dispatch(UserEvents::PASSWORD_RESET, new UserCrudEvent($user, $request));
       user_login_finalize($user);
       $this->logger->notice('User %name used one-time login link at time %timestamp.', ['%name' => $user->getDisplayName(), '%timestamp' => $timestamp]);
       drupal_set_message($this->t('You have just used your one-time login link. It is no longer necessary to use this link to log in. Please change your password.'));
diff --git a/core/modules/user/src/Entity/User.php b/core/modules/user/src/Entity/User.php
index 7529532..2a70668 100644
--- a/core/modules/user/src/Entity/User.php
+++ b/core/modules/user/src/Entity/User.php
@@ -9,7 +9,10 @@
 use Drupal\Core\Field\BaseFieldDefinition;
 use Drupal\Core\Language\LanguageInterface;
 use Drupal\user\RoleInterface;
+use Drupal\user\UserCrudEvent;
+use Drupal\user\UserEvents;
 use Drupal\user\UserInterface;
+use Symfony\Component\EventDispatcher\EventDispatcherInterface;
 
 /**
  * Defines the user entity class.
@@ -110,6 +113,12 @@ public function postSave(EntityStorageInterface $storage, $update = TRUE) {
         if ($this->id() == \Drupal::currentUser()->id()) {
           \Drupal::service('session')->migrate();
         }
+        else {
+          // Reset the flood control.
+          /** @var \Symfony\Component\EventDispatcher\EventDispatcherInterface $event_dispatcher */
+          $event_dispatcher = \Drupal::getContainer()->get('event_dispatcher');
+          $event_dispatcher->dispatch(UserEvents::PASSWORD_RESET, new UserCrudEvent($this, \Drupal::request()));
+        }
       }
 
       // If the user was blocked, delete the user's sessions to force a logout.
diff --git a/core/modules/user/src/EventSubscriber/UserCrudSubscriber.php b/core/modules/user/src/EventSubscriber/UserCrudSubscriber.php
new file mode 100644
index 0000000..cab03bf
--- /dev/null
+++ b/core/modules/user/src/EventSubscriber/UserCrudSubscriber.php
@@ -0,0 +1,93 @@
+<?php
+
+namespace Drupal\user\EventSubscriber;
+
+use Drupal\Core\Config\ConfigFactoryInterface;
+use Drupal\Core\Flood\FloodInterface;
+use Drupal\user\UserCrudEvent;
+use Drupal\user\UserEvents;
+use Symfony\Component\EventDispatcher\EventSubscriberInterface;
+
+/**
+ * Updates the current user's last access time.
+ */
+class UserCrudSubscriber implements EventSubscriberInterface {
+
+  /**
+   * The flood service.
+   *
+   * @var \Drupal\Core\Flood\FloodInterface
+   */
+  protected $flood;
+
+  /**
+   * The configuration factory.
+   *
+   * @var \Drupal\Core\Config\ConfigFactoryInterface
+   */
+  protected $configFactory;
+
+  /**
+   * Constructs a new UserRequestSubscriber.
+   *
+   * @param \Drupal\Core\Flood\FloodInterface $flood
+   *   The flood service.
+   * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
+   *   The configuration factory.
+   */
+  public function __construct(FloodInterface $flood, ConfigFactoryInterface $config_factory) {
+    $this->flood = $flood;
+    $this->configFactory = $config_factory;
+  }
+
+  /**
+   * Reset flood limit.
+   *
+   * @param \Drupal\user\UserCrudEvent $event
+   *   The event to process.
+   */
+  public function onPasswordReset(UserCrudEvent $event) {
+    // @todo: check if user has flood lock.
+    $user = $event->getUser();
+    $flood_config = $this->config('user.flood');
+    if ($flood_config->get('uid_only')) {
+      // Clear flood events based on the uid only if configured.
+      $identifier = $user->id();
+    }
+    else {
+      // The default identifier is a combination of uid and IP address.
+      $identifier = $user->id() . '-' . $event->getRequest()->getClientIP();
+    }
+    $this->flood->clear('user.failed_login_ip');
+    $this->flood->clear('user.failed_login_user', $identifier);
+  }
+
+  /**
+   * Retrieves a configuration object.
+   *
+   * This is the main entry point to the configuration API. Calling
+   * @code $this->config('book.admin') @endcode will return a configuration
+   * object in which the book module can store its administrative settings.
+   *
+   * @param string $name
+   *   The name of the configuration object to retrieve. The name corresponds to
+   *   a configuration file. For @code \Drupal::config('book.admin') @endcode,
+   *   the config object returned will contain the contents of book.admin
+   *   configuration file.
+   *
+   * @return \Drupal\Core\Config\Config
+   *   A configuration object.
+   */
+  protected function config($name) {
+    return $this->configFactory->get($name);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function getSubscribedEvents() {
+    $events[UserEvents::PASSWORD_RESET][] = ['onPasswordReset', 300];
+    return $events;
+  }
+
+}
diff --git a/core/modules/user/src/UserCrudEvent.php b/core/modules/user/src/UserCrudEvent.php
new file mode 100644
index 0000000..7afc6f3
--- /dev/null
+++ b/core/modules/user/src/UserCrudEvent.php
@@ -0,0 +1,60 @@
+<?php
+
+namespace Drupal\user;
+
+use Symfony\Component\EventDispatcher\Event;
+use Symfony\Component\HttpFoundation\Request;
+
+/**
+ * Wraps a user event for event listeners.
+ */
+class UserCrudEvent extends Event {
+
+  /**
+   * An user object.
+   *
+   * @var \Drupal\user\UserInterface
+   */
+  protected $user;
+
+  /**
+   * Request object.
+   *
+   * @var \Symfony\Component\HttpFoundation\Request
+   */
+  protected $request;
+
+  /**
+   * Constructs a user event object.
+   *
+   * @param \Drupal\user\UserInterface $user
+   *   User object.
+   * @param \Symfony\Component\HttpFoundation\Request $request
+   *   The request.
+   */
+  public function __construct(UserInterface $user, Request $request) {
+    $this->user = $user;
+    $this->request = $request;
+  }
+
+  /**
+   * Gets user object.
+   *
+   * @return \Drupal\user\UserInterface
+   *   The user object that caused the event to fire.
+   */
+  public function getUser() {
+    return $this->user;
+  }
+
+  /**
+   * Gets user object.
+   *
+   * @return \Symfony\Component\HttpFoundation\Request
+   *   Request object.
+   */
+  public function getRequest() {
+    return $this->request;
+  }
+
+}
diff --git a/core/modules/user/src/UserEvents.php b/core/modules/user/src/UserEvents.php
new file mode 100644
index 0000000..c81d113
--- /dev/null
+++ b/core/modules/user/src/UserEvents.php
@@ -0,0 +1,19 @@
+<?php
+
+namespace Drupal\user;
+
+/**
+ * Defines events for the user.
+ */
+final class UserEvents {
+
+  /**
+   * Name of the event fired when reset password.
+   *
+   * @Event
+   *
+   * @var string
+   */
+  const PASSWORD_RESET = 'user.password_reset';
+
+}
diff --git a/core/modules/user/user.services.yml b/core/modules/user/user.services.yml
index c273cb3..a37efaf 100644
--- a/core/modules/user/user.services.yml
+++ b/core/modules/user/user.services.yml
@@ -40,6 +40,11 @@ services:
     arguments: ['@current_user', '@entity.manager']
     tags:
       - { name: event_subscriber }
+  user_password_reset_subscriber:
+    class: Drupal\user\EventSubscriber\UserCrudSubscriber
+    arguments: ['@flood', '@config.factory']
+    tags:
+      - { name: event_subscriber }
   theme.negotiator.admin_theme:
     class: Drupal\user\Theme\AdminNegotiator
     arguments: ['@current_user', '@config.factory', '@entity.manager', '@router.admin_context']
