直接结论:这不是密码错了,是客户端和服务器在“握手时语言不通”——8.0默认用caching_sha2_password,而老客户端只认mysql_native_password,必须从服务端用户配置和客户端驱动两头同时处理。

直接结论:这不是密码错了,是客户端和服务器在“握手时语言不通”——8.0 默认用 caching_sha2_password,而老客户端只认 mysql_native_password,必须从服务端用户配置 + 客户端驱动两头同时处理。
查清楚当前用户到底用的什么认证插件
别猜,先看真实状态。连上 MySQL(比如用 root),执行:
SELECT user, host, plugin FROM mysql.user WHERE user = 'your_app_user';
常见错误现象:
- 看到
caching_sha2_password,但你的 Navicat / PHP / Java 应用报SQLSTATE[HY000] [2054]或ERROR 1251,基本就是它了 - 看到
mysql_native_password却还是连不上?那问题大概率在客户端缓存或驱动版本,不是服务端配置 - 看到
auth_socket或空值?说明账号根本没设密码,ALTER USER会失败,得先用SET PASSWORD补密码
ALTER USER 后仍连不上,三个最常漏掉的点
执行了 ALTER USER 'u'@'h' IDENTIFIED WITH mysql_native_password BY 'pwd' 却无效,原因通常是:
- 没运行
FLUSH PRIVILEGES:权限变更不刷新,新设置不会生效 - host 不匹配:应用连的是
'u'@'192.168.1.100',你改的是'u'@'localhost',查SELECT user, host FROM mysql.user确认来源 - 客户端没重启:Navicat、DBeaver、Java 连接池都可能复用旧连接上下文,关掉重开比重启 MySQL 更有效
Java/PHP/Python 驱动不升级,光改服务端等于白干
即使服务端已切回 mysql_native_password,驱动不匹配照样握手失败,尤其在连接池回收、长连接复用时偶发出错——这点最容易被忽略。
- Java:必须用
mysql-connector-java≥ 8.0.12;5.1.x 驱动根本不支持 8.0 认证协议 - PHP:
mysqli扩展需 PHP ≥ 7.4(对应mysqlnd≥ 8.0.0);PHP 7.3 及更早版本的mysqlnd无法协商caching_sha2_password - Python:停用已停止维护的
MySQLdb;改用pymysql或mysql-connector-python≥ 8.0.12
别碰 default_authentication_plugin 配置项
这个参数只在实例首次初始化时生效,升级后的实例改了它,对已有用户完全无效,也不会让老客户端突然变兼容。
真正要改的是用户级认证方式,不是全局配置。而且注意:mysql.user 在 8.0 是视图,不能 UPDATE,只能靠 ALTER USER 一条条重置。批量生成语句可以这样查:
SELECT CONCAT("ALTER USER '", user,"'@'", host,"' IDENTIFIED WITH mysql_native_password BY 'new_pwd_here';") FROM mysql.user WHERE plugin = 'caching_sha2_password';
但注意:authentication_string 是哈希值,不能直接当明文用;实际操作中必须人工提供真实密码,或先用强密码重置再改插件。
复杂点在于:认证插件切换不是单点问题,而是服务端用户配置、客户端驱动能力、连接池行为三者耦合的结果。任何一个环节没对齐,就可能在某个时间点突然断连——尤其是连接复用场景下,错误不会立刻暴露。











