根本原因是客户端不支持caching_sha2_password插件要求的RSA公钥交换或TLS加密,导致认证握手失败;旧版Navicat、PyMySQL、JDBC 5.x等因协议栈缺失而报ERROR 2059。

连不上不是密码错了,是客户端根本“听不懂”caching_sha2_password插件的握手协议——它要求 RSA 公钥交换或 TLS,而旧版 Navicat、PyMySQL、JDBC 5.x 等工具协议栈缺失,直接卡在认证阶段报 ERROR 2059 或 Authentication plugin 'caching_sha2_password' cannot be loaded。
先确认是不是这个插件惹的祸
用能连上的方式(比如 mysql -u root -p 本地 socket)登录 MySQL 命令行,执行:
SELECT user, host, plugin FROM mysql.user WHERE user = 'your_user';
重点看三列:
-
user和host必须完全匹配你连接字符串里的值——'root'@'localhost'、'root'@'127.0.0.1'、'root'@'%'是三个独立账号,漏查一个都白忙 - 如果
plugin列值为caching_sha2_password,且你用的是 Navicat 15 以下、PyMySQL - 云数据库(如阿里云 RDS)可能禁止查
mysql.user,但ALTER USER通常仍可用
改单个用户的认证插件(最稳、见效最快)
这是影响最小、适用性最广的操作,但极易因语法疏忽锁死账户:
安装、修复、更新或打包一个基于 Python 和 PyMySQL 实现的 Windows `mysql` 命令。适用于用户希望在 PowerShell/CMD 中输入 `mysql` 时重定向到 Python 实现、需要交互式输入 MySQL 连接信息、需要同步到当前用户本地 bin 目录,或需要将该能力封装成可公开复用的 Codex skill。
- 必须显式重设密码:
ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'MyPass123!';—— 只写IDENTIFIED WITH mysql_native_password不带BY,会清空密码,账户立刻不可用 - Navicat 默认走 TCP 连接,
host是'127.0.0.1'而非'localhost',所以得同步执行:ALTER USER 'root'@'127.0.0.1' IDENTIFIED WITH mysql_native_password BY 'MyPass123!'; - 远程用户要单独改:
ALTER USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY 'MyPass123!'; - 改完立刻执行:
FLUSH PRIVILEGES;,否则内存缓存不更新,新设置无效 - 如果提示
ERROR 1396,说明该用户不存在,得先CREATE USER再改
客户端也得配合,否则照样失败
服务端改完,客户端若不响应变化,连接仍会失败:
- Navicat 会缓存旧连接配置:必须关闭软件重开,或删掉旧连接重建;它不会自动感知服务端插件变更
- JDBC 连接字符串要加参数:
?allowPublicKeyRetrieval=true&useSSL=false(仅限内网可信环境),且驱动版本不能低于8.0.16 - PyMySQL 必须 ≥
1.0.2才原生支持caching_sha2_password;旧版要么升级,要么换mysql-connector-python - Node.js 的
mysql2需显式传参authPlugin: 'caching_sha2_password',且版本 ≥2.0.0 - 密码含
@或/时,URL 解析会出错——这类字符必须 URL 编码,否则连接字符串本身就不合法
别碰 default_authentication_plugin 配置项
在 /etc/my.cnf 的 [mysqld] 段加 default_authentication_plugin=mysql_native_password,或 Docker 启动加 --default-authentication-plugin=mysql_native_password,都只影响「之后新建的用户」,对已存在的 root、admin 等账号完全无效。
云数据库(RDS/CDB)通常禁写配置文件,这条路根本走不通;重启 MySQL 也不会让老用户自动切换插件,FLUSH PRIVILEGES 更不管这事。
真正容易被忽略的,从来不是 SQL 语句写错,而是 host 写成 localhost 却没同步处理 'root'@'localhost',或者 Navicat 缓存了错误的握手参数反复重试——这些细节比插件切换本身更常导致失败。


















