MySQL/MariaDB Changes and Passwords from MD5 to BCrypt 2026/04/17 by Ami Sapphire Last Updated: 2026/09/16 WARNING: You will need to manually create a hash of your password and insert them to the database if you are insane enough to use the BCrypt side of the script changes, as it does not check for the previous MD5 password hash! UPDATE 2026/04/18: There is now a fallback check for accounts with old insecure unsalted MD5 passwords! No warning messages for those, however (as of yet). UPDATE 2026/08/20: Added missing steps for user/login.php. UPDATE 2026/09/16: Password check and warning for users for MD5-hashed passwords in user/editbio.php. Also, adds two messages for languages/en.php. Also... add the one prerequisite explicitly for the database. Prerequisite Please convert the password column in [tableprefix'd] fanfiction_authors of your existing database from varchar(40) to varchar(255). Otherwise the resultant bcrypt password hash will be truncated! docs/settingstable.sql Line 62 Original line: ) ENGINE=MyISAM DEFAULT CHARSET=latin1; Change to: ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; -- docs/tables.sql Lines 15, 29, 53, 75, 92, 112, 141, 158, 172, 186, 198, 212, 228, 243, 259, 275, 290, 304, 320, 337, 356, 371, 397, 423, 441, 483, 552 Original line: ) ENGINE=MyISAM; Change to: ) ENGINE=InnoDB; Line 71 Original line: `password` varchar(40) NOT NULL default '0', Replace with: `password` varchar(255) NOT NULL default '0', -- install/install.php Line 195 Original Line: if ($_POST['password'] == $_POST['password2']) $encryptpassword = md5($_POST['password']); Replace with: if ($_POST['password'] == $_POST['password2']) $encryptpassword = password_hash($_POST['password'], PASSWORD_BCRYPT, ['cost' => 12]); Lines 496, 522, 537, 548, 562, 585, 596, 604, 612, 618, 627, 637, 646, 656, 666, 675, 694, 706, 719, 728, 758, 768, 781, 816, 956 Original lines: ) ENGINE=MyISAM;"); Replace with: ) ENGINE=InnoDB;"); Line 503 Original line: KEY `uid` (`uid`)) ENGINE=MyISAM;"); Replace with: KEY `uid` (`uid`)) ENGINE=InnoDB;"); -- admin/update.php Line 84 Original line: ) ENGINE=MyISAM; Replace with: ) ENGINE=InnoDB; -- admin/members.php Line 90 Original line: $encryppass = md5($pass); Replace with: $encryppass = password_hash($pass, PASSWORD_BCRYPT, ['cost' => 12]); -- user/editbio.php Line 53 Add this segment: // check for MD5 password hashes after a user logs in to edit their bio and warn them if their password is insecure // all MD5 hashes are 32 exact characters long, hexadecimal, 0-9 and a-f random // this set is a bit cursed... but it works $pwdcharlengthquery = dbquery("SELECT CHAR_LENGTH(password) FROM ".TABLEPREFIX."fanfiction_authors WHERE uid = ".USERUID.";"); $pwdlengthfetch = mysqli_fetch_row($pwdcharlengthquery); $pwdlengthstring = end($pwdlengthfetch); $pwdcheck = (int) $pwdlengthstring; if ($pwdcheck == 32) $output .= "
"._INSECUREPWD."

"; Lines 81, 92 [formerly Lines 71, 82] Original lines: $encryppass = md5($pass); Replace with: $encryppass = password_hash($pass, PASSWORD_BCRYPT, ['cost' => 12]); Line 166 [formerly Line 156] Original line: $encryppassword = md5($_POST['password']); Replace with: $encryppassword = password_hash($_POST['password'], PASSWORD_BCRYPT, ['cost' => 12]); Line 196 [formerly Line 186] Original line: $output .= write_message(_ACTIONSUCCESSFUL." ".(isset($_GET['uid']) ? _BACK2ADMIN : _BACK2ACCT)); Replace with: $output .= write_message(_ACTIONSUCCESSFUL." ".(isset($_GET['uid']) ? _BACK2ADMIN : _BACK2ACCT."
"._LOGINAGAIN)); -- user/login.php [WARNING: HAS NO FALLBACK TO CHECK FOR MD5 PASSWORDS!] Line 55 Original line: $encryptedpassword = md5($_POST['password']); Replace with: $encryptedpassword = $passwd['password']; Line 68 Original line: if($passwd['password'] == $encryptedpassword) { Replace with: if(password_verify($_POST['password'], $encryptedpassword) == $encryptedpassword) { user/login.php [UPDATE: Now comes with fallback check for MD5 passwords!] Line 55 Original line: $encryptedpassword = md5($_POST['password']); Replace with: $encryptedpasswordb = $passwd['password']; Add this line under Line 55: $encryptedpasswordm = md5($_POST['password']); Line 69 Original line: if($passwd['password'] == $encryptedpassword) { Replace with: if(password_verify($_POST['password'], $encryptedpasswordb) == $encryptedpasswordb) { Line 72 Original line: setcookie($sitekey."_salt", md5($passwd['email'] . $encryptedpassword), time()+60*60*24*30, "/"); Replace with: setcookie($sitekey."_salt", md5($passwd['email'] . $encryptedpasswordb), time()+60*60*24*30, "/"); Line 76 Original line: $_SESSION[$sitekey."_salt"] = md5($passwd['email'] . $encryptedpassword); Replace with: $_SESSION[$sitekey."_salt"] = md5($passwd['email'] . $encryptedpasswordb); Add this segment under line 83: else if($passwd['password'] == $encryptedpasswordm) { if(isset($_POST['cookiecheck'])) { setcookie($sitekey."_useruid",$passwd['uid'], time()+60*60*24*30, "/"); setcookie($sitekey."_salt", md5($passwd['email'] . $encryptedpasswordm), time()+60*60*24*30, "/"); } if(!isset($_SESSION)) session_start( ); $_SESSION[$sitekey."_useruid"] = $passwd['uid']; $_SESSION[$sitekey."_salt"] = md5($passwd['email'] . $encryptedpasswordm); $logincode = dbquery("SELECT * FROM ".TABLEPREFIX."fanfiction_codeblocks WHERE code_type = 'login'"); while($code = dbassoc($logincode)) { eval($code['code_text']); } } -- user/lostpassword.php Line 57 Original line: $encryppass = md5($_POST['password']); Replace with: $encryppass = password_hash($_POST['password'], PASSWORD_BCRYPT, ['cost' => 12]); -- languages/en.php Line 297 Add this line between ICQ and INVALIDEMAIL: define ("_INSECUREPWD", "Your password is hashed using unsalted MD5, a known insecure hashing algorithm. Please update your password so it can be converted to the more secure bcrypt."); Line 299 Add this line between INVALIDEMAIL and NEWACCOUNT: define ("_LOGINAGAIN", "However, if you have changed your password, you will have to login again.");