diff --git a/password_strength.install b/password_strength.install
index 0cbd2f6..fe86c19 100644
--- a/password_strength.install
+++ b/password_strength.install
@@ -37,4 +37,32 @@ function password_strength_requirements($phase) {
 function password_strength_uninstall() {
   variable_del('password_strength_default_required_score');
   variable_del('password_strength_default_password_length');
-}
\ No newline at end of file
+}
+
+/**
+ * Implements hook_schema().
+ */
+function password_strength_schema() {
+  $schema['password_strength_score'] = array(
+    'description' => 'Stores the password strength score of each user.',
+    'fields' => array(
+      'uid' => array(
+        'type' => 'int',
+        'not null' => TRUE,
+        'default' => 0,
+        'description' => 'The {users}.uid this score belongs to.',
+      ),
+      'score' => array(
+        'type' => 'int',
+        'default' => 0,
+        'description' => 'The password strength score for this user.',
+      ),
+    ),
+    'indexes' => array(
+      'uid' => array('uid', 'score'),
+    ),
+    'primary key' => array('uid'),
+  );
+
+  return $schema;
+}
diff --git a/password_strength.module b/password_strength.module
index 1b62d9a..d7db2bd 100644
--- a/password_strength.module
+++ b/password_strength.module
@@ -12,6 +12,37 @@ define('PASSWORD_STRENGTH_SCORE_STRONG', 3);
 define('PASSWORD_STRENGTH_SCORE_VERYSTRONG', 4);
 
 /**
+ * Implements hook_init().
+ */
+function password_strength_init() {
+  // Display a reminder that the password needs to be changed if the user just
+  // logged in. Don't run
+  // drupal_set_message() on POST requests to avoid displaying the message after
+  // a successful password change.
+  $allowed_paths = array(
+    password_strength_password_change_path(),
+    'user/logout',
+  );
+  if (!empty($_SESSION['password_strength_force_password_reset']) && !in_array(current_path(), $allowed_paths) && empty($_POST)) {
+    drupal_set_message(t('Your password does not meet the minimum complexity requirement. You must change your password to proceed on the site.'), 'error', FALSE);
+    $options = array('query' => drupal_get_destination());
+    drupal_goto(password_strength_password_change_path(), $options);
+  }
+}
+
+/**
+ * Implements hook_user_login().
+ */
+function password_strength_user_login(&$edit, $account) {
+  global $user;
+
+  // Check password strength score and force a reset if needed.
+  if ((int)password_strength_get_user_score($user->uid) < password_strength_required_score($user)) {
+    $_SESSION['password_strength_force_password_reset'] = TRUE;
+  }
+}
+
+/**
  * Implements hook_xautoload().
  */
 function password_strength_xautoload($api) {
@@ -184,9 +215,17 @@ function password_strength_form_password_submit($form, &$form_state) {
     return;
   }
   list($account, $strength) = _password_strength_form_helper($form, $form_state);
+  // We need to store the password strength before the raw password gets hashed
+  // by user_saved() in user_register_submit(). This ensures that the password
+  // strength is available in hook_user_insert().
+  $form_state['values']['password_strength_score'] = $strength;
   // Password has passed validation. Save strength and report change.
-  // Invoke password_strength_change hook.
-  module_invoke_all('password_strength_change', $account, $strength);
+  // Invoke password_strength_change hook if the account is fully-fledged. In
+  // the case of a new user, the uid is not yet available and this hook will be
+  // invoked in password_strength_user_insert() instead.
+  if ($account->uid > 0) {
+    module_invoke_all('password_strength_change', $account, $strength);
+  }
 }
 
 /**
@@ -598,3 +637,87 @@ function password_strength_required_score($account) {
 
   return $score;
 }
+
+/**
+ * Gets the password strength score of a given user.
+ *
+ * @param int $uid
+ *   User account id.
+ *
+ * @return int|null
+ *   The user password score, or null if the score is unknown.
+ */
+function password_strength_get_user_score($uid) {
+  $score = db_query('SELECT score from {password_strength_score} WHERE uid = :uid', array(':uid' => $uid))->fetchField();
+
+  return $score !== FALSE ? (int) $score : null;
+}
+
+/**
+ * Sets the password strength score of a given user.
+ *
+ * @param int $uid
+ *   User account id.
+ *
+ * @param int $score
+ *   Password score for this user account.
+ */
+function password_strength_set_user_score($uid, $score) {
+  db_merge('password_strength_score')
+    ->key(array(
+      'uid' => $uid,
+    ))
+    ->fields(array('score' => $score))
+    ->execute();
+}
+
+/**
+ * Deletes the password strength score of a given user.
+ *
+ * @param int $uid
+ *   User account id.
+ */
+function password_strength_delete_user_score($uid) {
+  db_delete('password_strength_score')
+    ->condition('uid', $uid)
+    ->execute();
+}
+
+/**
+ * Implements hook_password_strength_change().
+ */
+function password_strength_password_strength_change($account, $strength) {
+  // Register new password score for this user account.
+  password_strength_set_user_score($account->uid, $strength['score']);
+  unset($_SESSION['password_strength_force_password_reset']);
+}
+
+/**
+ * Implements hook_user_insert().
+ */
+function password_strength_user_insert(&$edit, $account, $category) {
+  if (!empty($edit['password_strength_score']) && $account->uid > 0) {
+    // New users do not yet have an uid during the validation and submission
+    // steps, so we have to invoked hook_password_strength_change() here.
+    module_invoke_all('password_strength_change', $account, $edit['password_strength_score']);
+  }
+}
+
+/**
+ * Implements hook_user_delete().
+ */
+function password_strength_user_delete($account) {
+  // Clean up password strength score for this deleted user.
+  password_strength_delete_user_score($account->uid);
+}
+
+/**
+ * Gets the path for password change for the current user.
+ *
+ * @return string
+ *   The custom path of the password change form for this current user.
+ */
+function password_strength_password_change_path() {
+  global $user;
+  return 'user/' . $user->uid . '/edit';
+}
diff --git a/tests/password_strength.test b/tests/password_strength.test
index 36a9759..0266c3b 100644
--- a/tests/password_strength.test
+++ b/tests/password_strength.test
@@ -32,7 +32,7 @@ class PasswordStrengthTestCase extends DrupalWebTestCase {
   function setUp() {
     parent::setUp('password_strength', 'composer_manager');
     $this->web_user = $this->drupalCreateUser();
-    $this->admin_user = $this->drupalCreateUser(array('administer site configuration'));
+    $this->admin_user = $this->drupalCreateUser(array('administer site configuration', 'administer users'));
   }
 
   /**
@@ -42,13 +42,28 @@ class PasswordStrengthTestCase extends DrupalWebTestCase {
     // Set required score to very weak and test that any password works.
     $this->setRequiredScore('0');
     $this->changePassword($this->web_user, 'Password1');
+    $this->assertTrue(password_strength_get_user_score($this->web_user->uid) === 0, t('User password score set.'));
     $this->changePassword($this->web_user, '35qzYI^HUbAZ');
+    $this->assertTrue(password_strength_get_user_score($this->web_user->uid) === 4, t('User password score set.'));
 
     // Set required score to very strong and test that a weak password fails and
     // that a strong password works.
     $this->setRequiredScore('4');
     $this->changePassword($this->web_user, 'Password1', TRUE);
+    $this->assertTrue(password_strength_get_user_score($this->web_user->uid) === 4, t('User password score remains the same.'));
     $this->changePassword($this->web_user, '35qzYI^HUbAZ');
+    $this->assertTrue(password_strength_get_user_score($this->web_user->uid) === 4, t('User password score set.'));
+
+    // Delete web user and verify password score gets cleaned up.
+    variable_set('user_cancel_method', 'user_cancel_reassign');
+    variable_set('password_strength_default_required_score', '0');
+    $this->drupalLogin($this->admin_user);
+    $this->drupalGet('user/' . $this->web_user->uid . '/edit');
+    $this->drupalPost(NULL, NULL, t('Cancel account'));
+    // Confirm deletion.
+    $this->drupalPost(NULL, NULL, t('Cancel account'));
+    $this->assertFalse(user_load($this->web_user->uid), 'User is not found in the database.');
+    $this->assertTrue(password_strength_get_user_score($this->web_user->uid) === null, t('User password score removed.'));
   }
 
   /**
