事故現場
- 工具:Navicat for MySQL 修改 root 密碼。
- 現象:應用(DedeCMS/PHP 5.2+)連線失敗,報錯:
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').
根因:舊版密碼雜湊 (16 字元) vs 新版 (41 字元)
- MySQL 4.1 前:
PASSWORD() 產生 16 字元雜湊 (old_passwords=1)。
- MySQL 4.1+:預設 41 字元雜湊 (
old_passwords=0),更安全。
- Navicat 修改密碼時若會話/全域
old_passwords=1,會生成 16 字元雜湊,導致新版驅動(mysqlnd、mysqli、PDO)拒絕連線。
徹底修復步驟
1. 關閉 old_passwords 模式
-- 當前會話
SET SESSION old_passwords = 0;
-- 全域永久(寫入 my.cnf [mysqld] 區段)
old_passwords = 0
-- 重啟 MySQL 生效
2. 重設所有用戶密碼為新格式
-- 查看當前雜湊長度
SELECT User, Host, LENGTH(Password) FROM mysql.user;
-- 16 = 舊格式,41 = 新格式
-- 逐個用戶重設(替換 'new_password' 為實際密碼)
UPDATE mysql.user SET Password = PASSWORD('new_password') WHERE User = 'root' AND Host = 'localhost';
UPDATE mysql.user SET Password = PASSWORD('new_password') WHERE User = 'root' AND Host = '127.0.0.1';
UPDATE mysql.user SET Password = PASSWORD('new_password') WHERE User = 'root' AND Host = '::1';
-- 其他業務用戶同理
FLUSH PRIVILEGES;
3. 驗證雜湊長度已變 41
SELECT User, Host, LENGTH(Password) FROM mysql.user;
-- 應全為 41
4. 重啟 MySQL 確保配置生效
service mysqld restart
一鍵修復腳本(謹慎執行,先備份 mysql.user)
#!/bin/bash
mysql -uroot -p'old_root_pass' -e "
SET old_passwords = 0;
UPDATE mysql.user SET Password = PASSWORD('NewStrongPass#2024') WHERE User = 'root';
FLUSH PRIVILEGES;
SELECT User, Host, LENGTH(Password) FROM mysql.user;
"
service mysqld restart
預防措施
my.cnf 明確設定 old_passwords = 0。
- 使用
mysql_native_password 認證插件(5.7+ 預設),避免 old_passwords 干擾:
ALTER USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY 'pass';
- 應用層升級驅動:PHP 5.6+ 用
mysqli/PDO_MySQL (mysqlnd),棄用 ext/mysql。