If you’ve recently upgraded from php 5.3 to a newer version (5.5, 5.6, 7.0) you may have encountered a nasty bug on your WordPress or Magento website:
SQLSTATE[HY000][2054]
The server requested authentication method unknown to the client [mysql_old_password]
Your application is no longer able to connect to the database! So, what’s going on here? In version 4.1 MySQL started introducing a new internal storage mechanism for passwords. When you connect to mysql in newer versions, it assumes your password hash will be 41 bytes long. The old versions assume they are 16 bytes long.
When you upgrade MySQL, it maintains a compatibility mode called old_passwords allowing you to continue using the 16 byte passwords. However, new versions of php do not allow you to continue using the 16 byte passwords. See this link.
To fix the problem, you need to force MySQL to use the new password format and update any old passwords which were stored using the incorrect format. If you’re on shared hosting, you will need to contact your hosting company as this change may require root access to both the server and mysql
Disable MySQL old_passwords
The first thing you want to do is update /etc/mysql/my.cnf. (This file may also be stored at /etc/my.cnf).
You should see some text like the below, which you will need to change:
## Change the below:
old_passwords=1;
## Change to:
old_passwords=0;
Once you’ve made this configuration change, you need to restart mysql:
sudo service mysql restart
Now you have instructed MySQL to process passwords in the new format.
Update Existing User Passwords
Now comes the harder part — you will need to re-hash existing user passwords to use the new format. Note that you must have the non-hashed (plaintext) password in order to update it. Otherwise you will need to simply reset the password to something new.
First, run the below command to get a list of current users and their password hashes:
SELECT host,user,password from mysql.user;
+-----------+------+-------------------------------------------+
| host | user | password |
+-----------+------+-------------------------------------------+
| localhost | root | 5ea2f2a3436125ss9 |
| localhost | alan | *11ADAA0470F690CC585086B716E32F4222294A59 |
| 127.0.0.1 | root | 5ea2f2a3436125ss9 |
+-----------+------+-------------------------------------------+
Notice the output of the above command. Do you see anything different between alan and root? Alan’s password is clearly in the new format (longer text) and root’s is in the old format (shorter text). So, we know that we need to update the root user to use the new password format. Also, due to the way mysql stores users, we need to update 2 entries for the hosts “localhost” and “127.0.0.1” (yes they’re considered to be different).
Run the below commands to update:
UPDATE mysql.user SET Password = PASSWORD('plaintext_password_here') WHERE User = 'root';
Flush Privileges
Those two commands will change the root user’s password to whatever plaintext_password_here is, and will ensure it’s in the new format. We then flush the privileges to ensure the update takes effect.
Once you’ve completed both of the above steps, you should see php be able to connect to mysql again over mysql, mysqli, or pdo!
Great information. Thanks for writing it!
Hi Alan,
I had this problem and used your solution.
It worked perfectly! … Much appreciated
I just installed mysql 8.0.11. The “user” table does NOT have a “Password” field.
mysql> describe mysql.user;
+————————+———————————–+——+—–+———————–+——-+
| Field | Type | Null | Key | Default | Extra |
+————————+———————————–+——+—–+———————–+——-+
| Host | char(60) | NO | PRI | | |
| User | char(32) | NO | PRI | | |
| Select_priv | enum(‘N’,’Y’) | NO | | N | |
| Insert_priv | enum(‘N’,’Y’) | NO | | N | |
| Update_priv | enum(‘N’,’Y’) | NO | | N | |
| Delete_priv | enum(‘N’,’Y’) | NO | | N | |
| Create_priv | enum(‘N’,’Y’) | NO | | N | |
| Drop_priv | enum(‘N’,’Y’) | NO | | N | |
| Reload_priv | enum(‘N’,’Y’) | NO | | N | |
| Shutdown_priv | enum(‘N’,’Y’) | NO | | N | |
| Process_priv | enum(‘N’,’Y’) | NO | | N | |
| File_priv | enum(‘N’,’Y’) | NO | | N | |
| Grant_priv | enum(‘N’,’Y’) | NO | | N | |
| References_priv | enum(‘N’,’Y’) | NO | | N | |
| Index_priv | enum(‘N’,’Y’) | NO | | N | |
| Alter_priv | enum(‘N’,’Y’) | NO | | N | |
| Show_db_priv | enum(‘N’,’Y’) | NO | | N | |
| Super_priv | enum(‘N’,’Y’) | NO | | N | |
| Create_tmp_table_priv | enum(‘N’,’Y’) | NO | | N | |
| Lock_tables_priv | enum(‘N’,’Y’) | NO | | N | |
| Execute_priv | enum(‘N’,’Y’) | NO | | N | |
| Repl_slave_priv | enum(‘N’,’Y’) | NO | | N | |
| Repl_client_priv | enum(‘N’,’Y’) | NO | | N | |
| Create_view_priv | enum(‘N’,’Y’) | NO | | N | |
| Show_view_priv | enum(‘N’,’Y’) | NO | | N | |
| Create_routine_priv | enum(‘N’,’Y’) | NO | | N | |
| Alter_routine_priv | enum(‘N’,’Y’) | NO | | N | |
| Create_user_priv | enum(‘N’,’Y’) | NO | | N | |
| Event_priv | enum(‘N’,’Y’) | NO | | N | |
| Trigger_priv | enum(‘N’,’Y’) | NO | | N | |
| Create_tablespace_priv | enum(‘N’,’Y’) | NO | | N | |
| ssl_type | enum(”,’ANY’,’X509′,’SPECIFIED’) | NO | | | |
| ssl_cipher | blob | NO | | NULL | |
| x509_issuer | blob | NO | | NULL | |
| x509_subject | blob | NO | | NULL | |
| max_questions | int(11) unsigned | NO | | 0 | |
| max_updates | int(11) unsigned | NO | | 0 | |
| max_connections | int(11) unsigned | NO | | 0 | |
| max_user_connections | int(11) unsigned | NO | | 0 | |
| plugin | char(64) | NO | | caching_sha2_password | |
| authentication_string | text | YES | | NULL | |
| password_expired | enum(‘N’,’Y’) | NO | | N | |
| password_last_changed | timestamp | YES | | NULL | |
| password_lifetime | smallint(5) unsigned | YES | | NULL | |
| account_locked | enum(‘N’,’Y’) | NO | | N | |
| Create_role_priv | enum(‘N’,’Y’) | NO | | N | |
| Drop_role_priv | enum(‘N’,’Y’) | NO | | N | |
| Password_reuse_history | smallint(5) unsigned | YES | | NULL | |
| Password_reuse_time | smallint(5) unsigned | YES | | NULL | |
+————————+———————————–+——+—–+———————–+——-+
49 rows in set (0.00 sec)
How can I use your solution?