diff --git a/phpass.install b/phpass.install
index e569405..c7af060 100644
--- a/phpass.install
+++ b/phpass.install
@@ -23,6 +23,16 @@ function phpass_install() {
 }
 
 /**
+ * Implements hook_uninstall().
+ */
+function phpass_uninstall() {
+  // This will almost never be called, but is useful for development.
+  variable_del('phpass_user_update_hash_count');
+  variable_del('phpass_user_update_cli_orderby');
+  variable_del('phpass_user_update_cli_count');
+}
+
+/**
  * Implements hook_enable().
  */
 function phpass_enable() {
@@ -32,22 +42,35 @@ function phpass_enable() {
     // Don't bother with batched operations.
     require_once dirname(__FILE__) . '/password.inc';
     //  Hash again all current hashed passwords.
-    $hash_count_log2 = 11;
-    $result = db_query("SELECT u.uid, u.pass FROM {users} u WHERE u.uid > 0");
-    while ($account = db_fetch_object($result)) {
-      // If the $account->pass value is not a MD5 hash (a 32 character
-      // hexadecimal string) then skip it.
-      if (!preg_match('/^[0-9a-f]{32}$/', $account->pass)) {
-        continue;
-      }
+    // Variables defined here should be overriden in $conf in settings.php if needed.
+    // The count is in log 2, so 11 means 2048 iterations. This is much lower than
+    // the standard 14 (by a fator of 8) for speed during mass conversion.
+    $hash_count_log2 = variable_get('phpass_user_update_hash_count', 11);
+    // An alternative ordering may be desired, such as 'u.login DESC'.
+    $order_by = variable_get('phpass_user_update_cli_orderby', 'u.uid ASC');
+    // Number of users to conver per iteration.
+    $count = variable_get('phpass_user_update_cli_count', 10000);
+    $from = 0;
+    do {
+      $has_rows = FALSE;
+      $result = db_query_range("SELECT u.uid, u.pass FROM {users} u WHERE u.uid > 0 ORDER BY " . $order_by, $from, $count);
+      $from += $count;
+      while ($account = db_fetch_object($result)) {
+        $has_rows = TRUE;
+        // If the $account->pass value is not a MD5 hash (a 32 character
+        // hexadecimal string) then skip it.
+        if (!preg_match('/^[0-9a-f]{32}$/', $account->pass)) {
+          continue;
+        }
 
-      $new_hash = user_hash_password($account->pass, $hash_count_log2);
-      if ($new_hash) {
-        // Indicate an updated password.
-        $new_hash  = 'U' . $new_hash;
-        db_query("UPDATE {users} set pass = '%s' WHERE uid = %d", $new_hash, $account->uid);
+        $new_hash = user_hash_password($account->pass, $hash_count_log2);
+        if ($new_hash) {
+          // Indicate an updated password.
+          $new_hash  = 'U' . $new_hash;
+          db_query("UPDATE {users} set pass = '%s' WHERE uid = %d", $new_hash, $account->uid);
+        }
       }
-    }
+    } while ($has_rows);
   }
   else {
     $t = get_t();
@@ -73,7 +96,7 @@ function phpass_enable() {
 function phpass_user_update_hashes(&$context) {
   $context['finished'] = 0;
   // Lower than DRUPAL_HASH_COUNT to make the update run at a reasonable speed.
-  $hash_count_log2 = 11;
+  $hash_count_log2 = variable_get('phpass_user_update_hash_count', 11);
   // Multi-part update.
   if (!isset($context['sandbox']['user_from'])) {
     $context['sandbox']['user_from'] = 0;
