Решение проблемы “mysqlnd cannot connect to MySQL 4.1+ using old authentication” для PHP 5.3
После обновления сервера БД на Percona Server 5.1.52-rel12.3 с удивлением обнаружил, что перестал коннектиться PhpMyAdmin, а также все веб-приложения на PHP. WTF?
Проблема
Оказывается, что в новом MySQL (ну и Percona) изменился алгоритм шифрования паролей, да так здорово, что стал несовместим со старыми клиентами. Так что вам придется пройти это, если вы планируете обновлять MySQL до 5.5 версии, или ставить Percona Server.
Причем коннекты через mysql_connect() в PHP будут работать нормально, т.к. там алгоритм тоже обновили.
The new mysqlnd library necessitates the use of MySQL 4.1’s newer 41-byte password format. Continued use of the old 16-byte passwords will cause mysql_connect() and similar functions to emit the error, “mysqlnd cannot connect to MySQL 4.1+ using old authentication.”
А вот коннекты через PDO (а Doctrine ORM да и Zend_Db работаю через PDO) осуществляться не будут, т.к. там апдейт пока не делали. В итоге при запуске веб-приложения мы увидим такую ошибку:
PDO Connection Error: SQLSTATE[HY000] [2000] mysqlnd cannot connect to MySQL 4.1+ using the old insecure authentication. Please use an administration tool to reset your password with the command SET PASSWORD = PASSWORD(‘your_existing_password’). This will store a new, and more secure, hash value in mysql.user. If this user is used in other scripts executed by PHP 5.2 or earlier you might need to remove the old-passwords flag from your my.cnf file
А PHPMyAdmin даже её показывать не будет, а просто скажет, что Mysql сервер не отвечает. Кстати, переключи язык на английский, он сообщит что не может залогиниться а не подконнектиться. Привет переводчикам!
Сама проблема заключается в том, что MySQL может хранить пароли в старом 16-символьном формате, но он не поддерживается в PHP 5.3 mysqlnd библиотеке. Погуглив я наткнулся на одну статью, которая помогла мне решить эту проблему без даунгрейда MySQL или PHP. Гуглить пришлось долго, поэтому я решил перевести и запостить её здесь.
Решение
Данный метод позволит решить проблему без даунгрейда PHP или MySQL.
1. Заставляем MySQL НЕ использовать старыйе пароли old_passwords
Это значит, что MySQL 5.x по прежнему используют старую схему генерации паролей. Для изменения этого надо удалить/закомментировать/присвоить 0 параметру old_passwords в секции [mysqld] конфига my.cnf
# old_passwrods = 1
Перезапустите MySQL и проверьте, какой из алгоритмов работает.
1 2 3 4 5 6 7 |
SELECT Length(PASSWORD('xyz')); +-------------------------+ | Length(PASSWORD('xyz')) | +-------------------------+ | 16 | +-------------------------+ 1 row in set (0.00 sec) |
Если работает старый алгоритм вы увидите 16, т.е. пароль 16ти смвольный. Если работает новый – 41.
2. Перегенерациф паролей
Для этого соеденитесь с БД через консольный mysql-клиент и выполните запрос:
1 |
SELECT user, Length(`Password`) FROM `mysql`.`user`; |
Потом вы увидите, у кого пароли старые, а у кого сгенерированные по новому алгоритму:
1 2 3 4 5 6 7 8 |
+----------+--------------------+ | user | Length(`Password`) | +----------+--------------------+ | root | 41 | | root | 16 | | user2 | 16 | | user2 | 16 | +----------+--------------------+ |
Важно знать, что один пользователь может иметь несколько записей паролей, для разных хостов.
Теперь необходимо собственно перегенерить пароли для тех юзеров, у кого они 16 символьные, и перезагрузить привелегии.
1 2 |
UPDATE mysql.user SET Password = PASSWORD('password') WHERE user = 'username'; FLUSH PRIVILEGES; |
Всё! Теперь PHPMyAdmin и другие PHP веб-приложения заработали!
Это потрясающе! Спасибо огромное
Пожалуйста, рад помочь!
Спасибо большое за статью! Очень помогли!
Спасибо большое! Помогло!
Спасибо! Мучался 2 дня..
Как выполнять запросы *???
?
Спасибо большое за статью!
“Важно знать, что один пользователь может иметь несколько записей паролей, для разных хостов.” – Что это значит, как один пользователь может иметь несколько типов паролей?
Это происходит потому, что в таблице mysql.user первичный ключ – составной {Host,User}
Спасибо! Мучился долго.
Правда этим не ограничилось. Через браузер после смены пароля у root долго выдается ошибка 1045 access denied, пришлось менять config.inc.php auth_type на http