diff --git a/auth/db/auth.php b/auth/db/auth.php
index e3582f5..10240cf 100644
--- a/auth/db/auth.php
+++ b/auth/db/auth.php
@@ -17,6 +17,7 @@ if (!defined('MOODLE_INTERNAL')) {
 }
 
 require_once($CFG->libdir.'/authlib.php');
+require_once($CFG->libdir.'/ddllib.php');
 
 /**
  * External database authentication plugin.
@@ -176,7 +177,7 @@ class auth_plugin_db extends auth_plugin_base {
             if ($rs = $authdb->Execute($sql)) {
                 if ( !$rs->EOF ) {
                     $fields_obj = rs_fetch_record($rs);
-                    $fields_obj = (object)array_change_key_case((array)$fields_obj , CASE_LOWER);                 
+                    $fields_obj = (object)array_change_key_case((array)$fields_obj , CASE_LOWER);
                     foreach ($selectfields as $localname=>$externalname) {
                         $result[$localname] = $textlib->convert($fields_obj->{$localname}, $this->config->extencoding, 'utf-8');
                      }
@@ -191,7 +192,7 @@ class auth_plugin_db extends auth_plugin_base {
 
 
     /**
-     * Change a user's password
+     * Change a user's password in internal or external database
      *
      * @param  object  $user        User table object  (with system magic quotes)
      * @param  string  $newpassword Plaintext password (with system magic quotes)
@@ -204,8 +205,63 @@ class auth_plugin_db extends auth_plugin_base {
         if ($this->config->passtype === 'internal') {
             return update_internal_user_password($user, $newpassword);
         } else {
-            // we should have never been called!
-            return false;
+
+            $username = $user->username;
+
+            $textlib = textlib_get_instance();
+            $extusername = $textlib->convert($username, 'utf-8', $this->config->extencoding);
+            $extpassword = $textlib->convert($newpassword, 'utf-8', $this->config->extencoding);
+
+            switch ($this->config->passtype) {
+                case 'md5':
+                    $extpassword = md5($extpassword);
+                    break;
+                case 'sha1':
+                    $extpassword = sha1($extpassword);
+                    break;
+                case 'plaintext':
+                default:
+                    break; // plaintext
+            }
+
+            if (isset($this->config->password_table) && !empty($this->config->password_table)) {
+                $table = $this->config->password_table;
+            } else {
+                $table = $this->config->table;
+            }
+
+            $authdb = $this->db_init();
+
+            $extpassword = $this->ext_addslashes($extpassword);
+            $extusername = $this->ext_addslashes($extusername);
+            $sql = "SELECT *
+                      FROM {$this->config->table}
+                     WHERE {$this->config->fielduser} = '{$extusername}'";
+
+             if (!$rs = $authdb->Execute($sql)) {
+                 $authdb->Close();
+                 debugging(get_string('auth_dbcantfinduser','auth_db'));
+                 return false;
+             }
+
+             if (!$rs->EOF) {
+
+                $sql = "UPDATE {$table}
+                           SET {$this->config->fieldpass} =  '{$extpassword}'
+                         WHERE {$this->config->fielduser} = '{$extusername}'";
+                if (!$authdb->Execute($sql)) {
+                    $authdb->Close();
+                    debugging(get_string('auth_dbcantconnect','auth_db'));
+                    return false;
+                }
+                $rs->Close();
+                $authdb->Close();
+                return true;
+            } else {
+                $rs->Close();
+                $authdb->Close();
+                return false;
+            }
         }
     }
 
@@ -225,64 +281,135 @@ class auth_plugin_db extends auth_plugin_base {
      *
      */
     function sync_users($do_updates=false) {
-
         global $CFG;
         $pcfg = get_config('auth/db');
 
-/// list external users
-        $userlist = $this->get_userlist();
-        $quoteduserlist = implode("', '", addslashes_recursive($userlist));
-        $quoteduserlist = "'$quoteduserlist'";
+        echo get_string('connectingexternaldb', 'auth_db'), "\n";
+        $externaldbconnection = $this->db_init();
 
-/// delete obsolete internal users
-        if (!empty($this->config->removeuser)) {
+        /// Define table user to be created
+        $temptable = $CFG->prefix . 'extuser';
+        $droptablesql[] = "DROP TEMPORARY TABLE IF EXISTS {$temptable}";
+        $createtemptablesql = "CREATE TEMPORARY TABLE {$temptable}
+                            (id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
+                             username VARCHAR(64),
+                             mnethostid INT(10) UNSIGNED NOT NULL,
+                             PRIMARY KEY (id),
+                             UNIQUE KEY unique_username_mnet (username,mnethostid))";
 
-            // find obsolete users
-            if (count($userlist)) {
-                $sql = "SELECT u.id, u.username, u.email, u.auth
-                        FROM {$CFG->prefix}user u
-                        WHERE u.auth='db' AND u.deleted=0 AND u.username NOT IN ($quoteduserlist)";
-            } else {
-                $sql = "SELECT u.id, u.username, u.email, u.auth
-                        FROM {$CFG->prefix}user u
-                        WHERE u.auth='db' AND u.deleted=0";
+        execute_sql_arr($droptablesql, true, false); /// Drop temp table to avoid persistence problems later
+
+        echo get_string('creatingtemptable', 'auth_db', 'tmp_extuser'), "\n";
+        if(! execute_sql($createtemptablesql, false) ){
+            echo "Failed to create temporary users table - aborting\n";
+            exit;
+        }
+
+        /// get users from external database and store in temporary table
+        $rs = $externaldbconnection->Execute("SELECT {$this->config->fielduser} AS username FROM {$this->config->table}");
+
+        if (!$rs) {
+            print_error('auth_dbcantgetusers','auth_db');
+        } else if (!$rs->EOF) {
+            echo get_string('inserting_users', 'auth_db'), "\n";
+            while ($rec = $rs->FetchRow()) {
+
+                $data = new stdclass();
+                $data->username = moodle_strtolower($rec['username']);
+                $data->mnethostid = $CFG->mnet_localhost_id;
+                insert_record($temptable, $data, false);
             }
+        }
+
+        /// preserve our user database
+        /// if the temp table is empty, it probably means that something went wrong, exit
+        /// so as to avoid mass deletion of users; which is hard to undo
+        $count = count_records_sql("SELECT COUNT(username) AS count, 1 FROM {$temptable}");
+        if ($count < 1) {
+            echo get_string('didntgetusersfromdb', 'auth_db'), "\n";
+            exit;
+        } else {
+            echo get_string('gotcountrecordsfromdb', 'auth_db', $count), "\n";
+        }
+
+        /// User removal
+        // Find users in DB that aren't in external db -- to be removed!
+        // this is still not as scalable (but how often do we mass delete?)
+        if ($this->config->removeuser !== AUTH_REMOVEUSER_KEEP) {
+            $sql = "SELECT u.id, u.username, u.email, u.auth
+                      FROM {$CFG->prefix}user u
+                 LEFT JOIN {$temptable} e
+                        ON (u.username = e.username AND
+                            u.mnethostid = e.mnethostid)
+                     WHERE u.auth = '{$this->authtype}'
+                       AND u.deleted = 0
+                       AND e.username IS NULL";
             $remove_users = get_records_sql($sql);
 
             if (!empty($remove_users)) {
-                print_string('auth_dbuserstoremove','auth', count($remove_users)); echo "\n";
+                echo get_string('userentriestoremove','auth_db', count($remove_users)), "\n";
 
                 foreach ($remove_users as $user) {
-                    if ($this->config->removeuser == 2) {
+                    if ($this->config->removeuser == AUTH_REMOVEUSER_FULLDELETE) {
                         if (delete_user($user)) {
-                            echo "\t"; print_string('auth_dbdeleteuser', 'auth', array($user->username, $user->id)); echo "\n";
+                            echo "\t",
+                                 get_string('removeduser', 'auth_db',
+                                            array($user->username, $user->id)),
+                                 "\n";
                         } else {
-                            echo "\t"; print_string('auth_dbdeleteusererror', 'auth', $user->username); echo "\n";
+                            echo "\t",
+                                 get_string('removeusererror', 'auth_db', $user->username),
+                                 "\n";
                         }
-                    } else if ($this->config->removeuser == 1) {
-                        $updateuser = new object();
+                    } else if ($this->config->removeuser == AUTH_REMOVEUSER_SUSPEND) {
+                        $updateuser = new stdClass();
                         $updateuser->id   = $user->id;
                         $updateuser->auth = 'nologin';
-                        if (update_record('user', $updateuser)) {
-                            echo "\t"; print_string('auth_dbsuspenduser', 'auth', array($user->username, $user->id)); echo "\n";
-                        } else {
-                            echo "\t"; print_string('auth_dbsuspendusererror', 'auth', $user->username); echo "\n";
-                        }
+                        update_record('user', $updateuser);
+                        echo "\t",
+                             get_string('suspendeduser', 'auth_db',
+                                        array($user->username, $user->id)),
+                             "\n";
                     }
                 }
+            } else {
+                echo get_string('nouserentriestoremove', 'auth_db'), "\n";
             }
             unset($remove_users); // free mem!
         }
 
-        if (!count($userlist)) {
-            // exit right here
-            // nothing else to do
-            return true;
+        /// Revive suspended users
+        if (!empty($this->config->removeuser) and $this->config->removeuser == AUTH_REMOVEUSER_SUSPEND) {
+            $sql = "SELECT u.id, u.username
+                      FROM {$CFG->prefix}user u
+                      JOIN {$temptable} e
+                        ON (u.username = e.username AND
+                            u.mnethostid = e.mnethostid)
+                     WHERE u.auth = 'nologin'
+                       AND u.deleted = 0";
+            $revive_users = get_records_sql($sql);
+
+            if (!empty($revive_users)) {
+                echo get_string('userentriestorevive', 'auth_db', count($revive_users)), "\n";
+
+                foreach ($revive_users as $user) {
+                    $updateuser = new stdClass();
+                    $updateuser->id = $user->id;
+                    $updateuser->auth = $this->authtype;
+                    update_record('user', $updateuser);
+                    echo "\t",
+                         get_string('reviveduser', 'auth_db',
+                                    array($user->username, $user->id)),
+                         "\n";
+                }
+            } else {
+                echo get_string('nouserentriestorevive', 'auth_db'), "\n";
+            }
+
+            unset($revive_users);
         }
 
-        ///
-        /// update existing accounts
-        ///
+        /// User Updates
         if ($do_updates) {
             // narrow down what fields we need to update
             $all_keys = array_keys(get_object_vars($this->config));
@@ -294,91 +421,93 @@ class auth_plugin_db extends auth_plugin_base {
                     }
                 }
             }
-            // print_r($all_keys); print_r($updatekeys);
             unset($all_keys); unset($key);
-
-            // only go ahead if we actually
-            // have fields to update locally
-            if (!empty($updatekeys)) {
-                $sql = 'SELECT u.id, u.username
-                        FROM ' . $CFG->prefix .'user u
-                        WHERE u.auth=\'db\' AND u.deleted=\'0\' AND u.username IN (' . $quoteduserlist . ')';
-                if ($update_users = get_records_sql($sql)) {
-                    print "User entries to update: ". count($update_users). "\n";
-
-                    foreach ($update_users as $user) {
-                        echo "\t"; print_string('auth_dbupdatinguser', 'auth', array($user->username, $user->id));
-                        if (!$this->update_user_record(addslashes($user->username), $updatekeys)) {
-                            echo " - ".get_string('skipped');
-                        }
-                        echo "\n";
-                    }
-                    unset($update_users); // free memory
-                }
-            }
+        } else {
+            echo get_string('nouserentriestoupdate', 'auth_db'), "\n";
         }
 
+        if ($do_updates and !empty($updatekeys)) { // run updates only if relevant
+            $users = get_records_sql("SELECT u.username, u.id
+                                        FROM {$CFG->prefix}user u
+                                       WHERE u.deleted = 0
+                                         AND u.auth = '{$this->authtype}'
+                                         AND u.mnethostid = {$CFG->mnet_localhost_id}");
+
+            if (!empty($users)) {
+                echo get_string('userentriestoupdate', 'auth_db', count($users)), "\n";
 
-        ///
-        /// create missing accounts
-        ///
-        // NOTE: this is very memory intensive
-        // and generally inefficient
-        $sql = 'SELECT u.id, u.username
-                FROM ' . $CFG->prefix .'user u
-                WHERE u.auth=\'db\' AND u.deleted=\'0\'';
+                $xcount = 0;
+                $maxxcount = 100;
 
-        $users = get_records_sql($sql);
+                foreach ($users as $user) {
+                    echo "\t";
+                    if ($this->update_user_record($user->username, $updatekeys)) {
+                        echo get_string('updateduser', 'auth_db', array($user->username, $user->id));
+                    } else {
+                        echo get_string('skippeduser', "auth_db", array($user->username, $user->id));
+                    }
 
-        // simplify down to usernames
-        $usernames = array();
-        if (!empty($users)) {
-            foreach ($users as $user) {
-                array_push($usernames, $user->username);
+                    echo "\n";
+                    $xcount++;
+                }
+                unset($users); // free mem
             }
-            unset($users);
+        } else { // end do updates
+            echo get_string('nouserentriestoupdate', 'auth_db'), "\n";
         }
 
-        $add_users = array_diff($userlist, $usernames);
-        unset($usernames);
+
+        /// User Additions
+        // Find users missing in DB that are in EXTERNAL DB
+        // and gives me a nifty object I don't want.
+        // note: we do not care about deleted accounts anymore, this feature was replaced by suspending to nologin auth plugin
+        $sql = "SELECT e.id, e.username
+                  FROM {$temptable} e
+             LEFT JOIN {$CFG->prefix}user u
+                    ON (e.username = u.username AND
+                        e.mnethostid = u.mnethostid)
+                 WHERE u.id IS NULL";
+        $add_users = get_records_sql($sql);
 
         if (!empty($add_users)) {
-            print_string('auth_dbuserstoadd','auth',count($add_users)); echo "\n";
-            begin_sql();
+            echo get_string('userentriestocreate','auth_db',count($add_users)), "\n";
+
             foreach($add_users as $user) {
-                $username = $user;
-                $user = $this->get_userinfo_asobj($user);
+                $user = $this->get_userinfo_asobj($user->username);
 
                 // prep a few params
-                $user->username   = $username;
+                $user->username   = $user->username;
                 $user->modified   = time();
                 $user->confirmed  = 1;
                 $user->auth       = 'db';
                 $user->mnethostid = $CFG->mnet_localhost_id;
+                // get_userinfo_asobj() might have replaced $user->username with the value
+                // from the EXTERNAL DB server (which can be mixed-case). Make sure it's lowercase
+                $user->username = trim(moodle_strtolower($user->username));
                 if (empty($user->lang)) {
                     $user->lang = $CFG->lang;
                 }
 
                 $user = addslashes_object($user);
-                // maybe the user has been deleted before
-                if ($old_user = get_record('user', 'username', $user->username, 'deleted', 1, 'mnethostid', $user->mnethostid)) {
-                    $user->id = $old_user->id;
-                    set_field('user', 'deleted', 0, 'username', $user->username);
-                    echo "\t"; print_string('auth_dbreviveduser', 'auth', array(stripslashes($user->username), $user->id)); echo "\n";
-                } elseif ($id = insert_record ('user',$user)) { // it is truly a new user
-                    echo "\t"; print_string('auth_dbinsertuser','auth',array(stripslashes($user->username), $id)); echo "\n";
-                    // if relevant, tag for password generation
-                    if ($this->config->passtype === 'internal') {
-                        set_user_preference('auth_forcepasswordchange', 1, $id);
-                        set_user_preference('create_password',          1, $id);
-                    }
-                } else {
-                    echo "\t"; print_string('auth_dbinsertusererror', 'auth', $user->username); echo "\n";
+
+                $id = insert_record('user',$user);
+                echo "\t",
+                     get_string('createduser', 'auth_db', array(stripslashes($user->username), $id)),
+                     "\n";
+                // if relevant, tag for password generation
+                if ($this->is_internal()) {
+                    set_user_preference('auth_forcepasswordchange', 1, $id);
+                    set_user_preference('create_password',          1, $id);
                 }
             }
-            commit_sql();
             unset($add_users); // free mem
+        } else {
+            echo get_string('nouserentriestocreate', 'auth_db'), "\n";
         }
+
+        execute_sql_arr($droptablesql, true, false); /// Drop temp table to avoid persistence problems later
+        $externaldbconnection->Close();
+
         return true;
     }
 
@@ -407,30 +536,6 @@ class auth_plugin_db extends auth_plugin_base {
     }
 
 
-    function get_userlist() {
-
-    /// Init result value
-        $result = array();
-
-        $authdb = $this->db_init();
-
-        // fetch userlist
-        $rs = $authdb->Execute("SELECT {$this->config->fielduser} AS username
-                                FROM   {$this->config->table} ");
-
-        if (!$rs) {
-            print_error('auth_dbcantconnect','auth');
-        } else if ( !$rs->EOF ) {
-            while ($rec = rs_fetch_next_record($rs)) {
-                $rec = (object)array_change_key_case((array)$rec , CASE_LOWER);
-                array_push($result, $rec->username);
-            }
-        }
-
-        $authdb->Close();
-        return $result;
-    }
-
     /**
      * reads userinformation from DB and return it in an object
      *
@@ -587,7 +692,7 @@ class auth_plugin_db extends auth_plugin_base {
      * @return bool
      */
     function can_change_password() {
-        return ($this->config->passtype == 'internal' or !empty($this->config->changepasswordurl));
+        return true;
     }
 
     /**
@@ -597,12 +702,10 @@ class auth_plugin_db extends auth_plugin_base {
      * @return string
      */
     function change_password_url() {
-        if ($this->config->passtype == 'internal') {
-            // standard form
-            return '';
-        } else {
-            // use custom url
+        if (isset($this->config->changepasswordurl) && !empty($this->config->changepasswordurl)) {
             return $this->config->changepasswordurl;
+        } else {
+            return '';
         }
     }
 
@@ -612,7 +715,7 @@ class auth_plugin_db extends auth_plugin_base {
      * @return bool
      */
     function can_reset_password() {
-        return ($this->config->passtype == 'internal');
+        return true;
     }
 
     /**
@@ -653,6 +756,9 @@ class auth_plugin_db extends auth_plugin_base {
         if (!isset($config->table)) {
             $config->table = '';
         }
+        if (!isset($config->password_table)) {
+            $config->password_table = '';
+        }
         if (!isset($config->fielduser)) {
             $config->fielduser = '';
         }
@@ -687,6 +793,7 @@ class auth_plugin_db extends auth_plugin_base {
         set_config('user',          $config->user,          'auth/db');
         set_config('pass',          $config->pass,          'auth/db');
         set_config('table',         $config->table,         'auth/db');
+        set_config('password_table',$config->password_table,'auth/db');
         set_config('fielduser',     $config->fielduser,     'auth/db');
         set_config('fieldpass',     $config->fieldpass,     'auth/db');
         set_config('passtype',      $config->passtype,      'auth/db');
diff --git a/auth/db/config.html b/auth/db/config.html
index e4ccbe3..ca16aa5 100644
--- a/auth/db/config.html
+++ b/auth/db/config.html
@@ -22,6 +22,9 @@
     if (!isset($config->table)) {
         $config->table = '';
     }
+    if (!isset($config->password_table)) {
+        $config->password_table = '';
+    }
     if (!isset($config->fielduser)) {
         $config->fielduser = '';
     }
@@ -200,6 +203,21 @@
 </tr>
 
 <tr valign="top" class="required">
+    <td align="right"><label for="password_table"><?php print_string("auth_dbpasswordtable_key", "auth") ?></label></td>
+    <td>
+        <input id="password_table" name="password_table" type="text" size="30" value="<?php echo $config->password_table?>" />
+        <?php
+
+        if (isset($err["password_table"])) {
+            formerr($err["password_table"]);
+        }
+
+        ?>
+    </td>
+    <td><?php print_string("auth_dbpasswordtable", "auth") ?></td>
+</tr>
+
+<tr valign="top" class="required">
     <td align="right"><label for="extencoding"><?php print_string("auth_dbextencoding", "auth") ?></label></td>
     <td>
         <input id="extencoding" name="extencoding" type="text" value="<?php echo $config->extencoding ?>" />
