
相信不少朋友第一次在项目里切换到 MySQL 8.0 时都被这条报错狠狠折磨过Client does not support authentication protocol requested by server; consider upgrading MySQL client短的一行英文信息量却很大。明明数据库装好了、账号密码都对、端口也通可客户端就是连不上去。更让人头疼的是网上搜到的解决方案五花八门有让你改my.cnf的、有让你重装驱动的、还有让你降级 MySQL 的看了一圈更乱了。这篇文章不谈虚的咱们把这条报错彻底讲透。从 MySQL 8.0 为什么要改认证协议讲起到不同场景下到底该用哪种解法再到实际操作时最容易踩的坑全部过一遍。不管你用的是 Navicat、PHP、Python、Java JDBC 还是 Docker 里的 MySQL 容器看完都能找到对应的处理思路。1. 问题全貌与根因剖析这条报错的英文全称是Client does not support authentication protocol requested by server; consider upgrading MySQL client翻译过来就是客户端不支持服务器要求的认证协议请考虑升级你的 MySQL 客户端。报错本质不是密码错误也不是网络不通而是客户端和服务端在认证方式上谈不拢。1.1 一切源于 MySQL 8.0 的默认认证插件变更MySQL 5.7 及更早版本默认的认证插件是mysql_native_password。这个插件从 MySQL 4.1 时代就开始用二十年下来几乎所有客户端、驱动、GUI 工具都兼容它可以说是最大公约数。到了 MySQL 8.0官方把默认认证插件换成了caching_sha2_password。名字虽然拗口但它的设计初衷是好的比老插件具备更强的密码安全性基于 SHA-256 的哈希算法配合服务端的缓存机制能有效避免密码在传输过程中的风险。问题就出在这里。你数据库版本升到了 8.0默认按新插件创建用户但你的客户端还是按老规矩用mysql_native_password来打招呼。服务端说我要用 caching_sha2_password 和你认证客户端说我只懂 mysql_native_password两边一对话就崩了于是抛出这条报错。1.2 哪些客户端会踩中这个坑搞清楚这个根因后哪些场景容易出问题就很好判断了。只要客户端的语言版本对应不上新插件的都会中招老版本 Navicat特别是 11.x、12.x 时代确切说 16.x 之前的一些版本对 MySQL 8.0 的 caching_sha2_password 支持不完整。PHP 的 mysql 扩展 / mysqli 扩展版本过低PHP 5.x、7.0 时代的老驱动不认识新插件。Python 的 pymysql / MySQLdb老版本库在初始化连接时没有按新插件处理密码报文。Java 的 JDBC 驱动mysql-connector-java 5.1.x 系列基本无力支撑8.0.x 系列才完整支持。命令行 mysql 客户端版本过旧比如系统自带的是 MySQL 5.5/5.6 时代的客户端去连 8.0 服务端大概率报错。1.3 顺带理清到底谁在坚持老协议这里有一个容易混淆的点。MySQL 8.0 服务端并不是只支持新插件它依然保留了对mysql_native_password的兼容能力。换句话说服务端是能说新话也能说老话的只是默认情况下创建用户时用的是新插件。问题更多出在客户端那头——客户端太老了只会说老话而服务端默认行为是新话两者就错位了。所以解决思路不外乎两个方向要么让服务端迁就客户端把用户的认证插件改回老的mysql_native_password要么让客户端跟上服务端升级组件、驱动或连接器使其支持caching_sha2_password。在我实际处理过的项目里这两种思路都有各自的适用场景下面逐个拆开讲。2. 两种解决方向与选型考量解决这条报错大的方向就两条修改服务端用户认证方式、升级客户端组件版本。听起来简单但选哪个方向得结合你的项目实际情况来判断选错了后面会埋雷。2.1 方向一修改服务端用户认证插件快速见效这种做法的核心命令就一条ALTER USER usernamehost IDENTIFIED WITH mysql_native_password BY password;把用户的认证方式从caching_sha2_password改成mysql_native_password客户端的老驱动立刻就能连上了。我见过很多团队遇到报错后直接在命令行执行这条马上解决问题效率确实高。但请注意这个操作有一个需要权衡的地方mysql_native_password的安全性比caching_sha2_password低一档。它虽然也做哈希但算法相对旧在暴力破解面前防护能力弱一些。如果你的数据库直接暴露在公网或者对安全等级有硬性要求比如等保测评、金融行业规范这种降级操作要慎重考虑尽量别用。还有一点如果你用的是 MySQL 8.0 默认配置my.cnf里并没有显式写default_authentication_plugin那么修改用户后新用户依然默认按新插件创建你得记得对每个需要的用户都执行一遍修改或者干脆在配置里写死默认插件后面会细说。2.2 方向二升级客户端组件治本第二种思路是让客户端去适配新协议。具体来说Navicat升级到 16.x 或更新版本完整支持 MySQL 8.0 认证。Java JDBC把mysql-connector-java换到 8.0.x 以上新版驱动类名从com.mysql.jdbc.Driver变成了com.mysql.cj.jdbc.Driver同时 URL 里通常要加allowPublicKeyRetrievaltrueuseSSLfalse等参数。PHP 环境PDO 的mysqlnd驱动在 PHP 7.2 之后就支持了 caching_sha2_password升级即可。Pythonpymysql 在 0.9.3 之后的版本支持新认证升级pip install --upgrade pymysql就能解决。命令行客户端升级到 8.0 对应的 mysql-client 版本。治本方案的好处是不会有安全降级但坏处也很明显升级组件行为可能会影响整个项目环境遇到老系统比如某个上了年纪的 PHP 项目跑在 CentOS 6 上不一定能轻轻松松完成升级。2.3 我的选型建议简单总结一下我的经验场景推荐方案原因本地开发环境、内网测试环境修改认证插件快、省事安全风险可控生产环境、公网暴露升级客户端组件保持高安全等级不降级协议老项目无法升级依赖修改认证插件等保不严格时兼容性优先Docker 容器内的 MySQL根据客户端情况二选一容器操作要额外注意见下文第三节这里还想提一句不要一上来就全局改my.cnf。除非你的客户端生态已经固定死且无法升级比如公司内部统一用老版 Navicat否则优先改单个用户而不是改全局默认影响面小得多。3. 实操过程与核心环节实现方向定了接下来手把手走一遍。我分别给出命令行直接操作和 Docker 容器两种场景的完整流程顺带把 Navicat、Python 连接时的关键配置也带出来。3.1 命令行直接修改用户认证插件第一步用 root 或其他有权限的账号进入 MySQLmysql -uroot -p输入密码进入后先确认当前用户的认证插件状态。注意 MySQL 8.0 的用户信息存在mysql.user表里插件字段在plugin列SELECT user, host, plugin FROM mysql.user WHERE user youruser;输出里你会看到类似caching_sha2_password的记录这就对应了报错来源。第二步执行修改ALTER USER youruserlocalhost IDENTIFIED WITH mysql_native_password BY yourpassword;这里有两个细节必须说清楚。细节一host到底写什么。如果你的程序是远程连接localhost就要改成%或者对应的 IP 段。我见过太多人在这里卡壳——明明本地用 root 执行成功了程序远程连接还是报错就是因为本地用户和远程用户是两个不同的账户记录。MySQL 的账号由user host共同决定别只盯着用户名看。细节二IDENTIFIED WITH和IDENTIFIED BY的关系。上面的写法等价于指定插件方式并设置密码为指定串。如果只是想改插件、保留现有密码老版本里有过一种写法ALTER USER youruserlocalhost IDENTIFIED WITH mysql_native_password;但实际测试中发现部分 MySQL 8.0 版本对这种省略密码的写法支持不友好可能会报语法错误。稳妥起见还是显式带上BY password明确告诉数据库插件换成老的密码用这个。第三步刷新权限并验证FLUSH PRIVILEGES;刷新不是必须的ALTER USER 隐含生效但养成习惯总没坏处。验证连接时退出后重新用你的客户端工具连一次。如果之前的报错消失说明问题解决。3.2 在 MySQL 8.0 下创建新用户时直接指定老插件如果你刚装好 MySQL 8.0还没建用户那更简单创建用户时直接指定插件就行CREATE USER newuser% IDENTIFIED WITH mysql_native_password BY password123; GRANT ALL PRIVILEGES ON yourdb.* TO newuser%; FLUSH PRIVILEGES;这个操作里的%表示允许从任意主机连接。如果只想允许本机用localhost如果只想允许某个固定 IP写具体地址。需要注意MySQL 8.0 安装完成后root 用户的 host 默认是localhost。有些教程让你把 root 改成%我不推荐这么干——root 是超级账号远程登录风险太高。正确做法是建一个业务专用账号按需授权root 留作本地管理。3.3 Docker 容器里的特殊处理很多人喜欢用 Docker 跑 MySQL 8.0比如执行这样的命令快速建容器docker run -d --name mysql8 -p 3306:3306 -e MYSQL_ROOT_PASSWORDroot123 mysql:8.0如果你在宿主机上用命令行客户端连接遇到同样的认证报错处理方式还不太一样。容器内的 MySQL 是全新安装的默认用户 root 用的是新认证插件此时你有两个选择。选择一进容器执行 SQL。docker exec -it mysql8 mysql -uroot -p进入 MySQL 命令行后执行ALTER USER root% IDENTIFIED WITH mysql_native_password BY root123; FLUSH PRIVILEGES;但这里有个坑容器环境下root 的 host 可能不是%而是localhost或127.0.0.1。取决于你的启动命令和官方镜像初始化脚本的行为。不确定时先查SELECT user, host, plugin FROM mysql.user;看到root对应的确切 host 再改别盲目猜。选择二启动容器时通过环境变量指定认证插件。MySQL 官方 Docker 镜像很早就支持MYSQL_ROOT_PASSWORD、MYSQL_DATABASE等环境变量但认证插件相关的是--default-authentication-plugin这个 mysqld 参数。在 Docker 里可以通过命令追加的方式传递docker run -d --name mysql8 -p 3306:3306 \ -e MYSQL_ROOT_PASSWORDroot123 \ mysql:8.0 --default-authentication-pluginmysql_native_password注意参数要放在镜像名后面因为它实际上是传给了 MySQL 容器的启动命令。这样容器初次初始化时创建的用户就都使用老插件。这个方法适合我再也不想折腾认证问题了的场景但同样有安全降级的顾虑不建议在生产环境无脑用。3.4 Navicat 场景的处理细节如果不想改服务端而是想通过升级 Navicat 解决建议升级到 16.x 版本。验证是否支持的简易方法连接时如果报错信息消失、正常出现输密码的交互说明认证兼容。如果还是报错再退回用 ALTER USER 方案。还有个细节Navicat 连接 MySQL 8.0 时如果连接参数里允许保持连接或使用 SSL设置跟服务端不匹配也可能出现其他异常。顺手把连接属性里useSSL的开关状态换一下再试排除干扰项。3.5 Python / Node.js 程序的配置要点Python 场景pymysql 老版本不支持 caching_sha2_password最简单的修复是升级到新版pip install --upgrade pymysql如果你无法升级比如受限于项目的依赖锁定那么在数据库端把对应用户改成 mysql_native_password并且连接时通常不需要额外参数因为老插件下握手是明文的。使用 MySQL 官方的mysql-connector-python在连接字串里加上auth_pluginmysql_native_password也行但这个选项会随着 MySQL 版本更新被逐步弃用建议优先考虑升级库版本。Node.js 场景mysql2驱动是目前支持 MySQL 8.0 认证最稳的选择。mysql也就是mysqljs/mysql老版本对新协议支持不好代码里会报同样的错误。把连接方式改成const mysql require(mysql2/promise); const conn await mysql.createConnection({ host: localhost, user: youruser, password: yourpassword, database: yourdb });mysql2底层实现了 caching_sha2_password 的握手流程所以无需改数据库端。3.6 补充通过配置全局默认插件还有一种一了百了的改法修改 MySQL 配置文件my.cnf在[mysqld]段下加一行default_authentication_pluginmysql_native_password然后重启 MySQL 服务。这样新建的所有用户包括之后 CREATE USER 的都会默认使用老认证插件。这条命令只影响新创建的用户已存在的用户不会被改变所以早期踩过坑的用户仍然要用 ALTER USER 单独修。之所以不推荐上来就改全局是因为它影响面太大而且把 MySQL 8.0 的安全特性人为关闭了。如果你团队里有人专门负责安全这个操作大概率会被打回。4. 常见问题与排查技巧实录处理和这个报错相关的线上问题时我积累了一些排查技巧也发现了一些文档里不太会写清楚的坑。整理出来希望帮你少走弯路。4.1 问题速查表问题现象可能原因处理办法客户端连不上报 authentication protocol 错误客户端太老不认识 caching_sha2_password升客户端或 ALTER USER 改插件root 本地可连远程程序连不上远程用户的 host 和本地不是同一个查 mysql.user 确认 host按需创建远程账号改了 ALTER USER 但程序还是报错密码缓存 / 连接池老连接未释放重启程序或连接池确认没有中间代理缓存Docker 容器改完用户后重启失效容器重建 / 数据卷未持久化用 volume 持久化数据或启动命令配插件修改 mysql.user 表直接 UPDATE plugin 报错MySQL 8.0 不允许直接 UPDATE plugin 字段用 ALTER USER 语法不要手动 UPDATE新版 Navicat 连接报 Authentication plugin caching_sha2_password cannot be loaded某些 Linux 版本图形工具依赖缺失更新工具或改服务端用户插件JDBC 连接时报 Public Key Retrieval 错误新版驱动要求 fetch 服务端公钥URL 加 allowPublicKeyRetrievaltrue 并配合 useSSLfalse4.2 一个容易出问题的细节mysql_native_password 的密码兼容ALTER USER userhost IDENTIFIED WITH mysql_native_password BY password这个操作在 MySQL 8.0 里是支持的。但有个冷知识老插件保存密码哈希时用的是 41 字节的*开头哈希串。如果你从旧版本数据库导出用户再导入 8.0可能会碰到哈希格式不兼容的情况。这种场景一般出现在数据库跨大版本迁移时解决办法是用SET PASSWORD重新生成哈希不要把老库的 user 表直接搬到新库。4.3 排查思路的核心要点不管遇到什么客户端先做三件事第一步进数据库查用户插件SELECT user, host, plugin FROM mysql.user WHERE user 你的用户名;第二步确认客户端的连接协议版本。命令行可以用mysql --version这一步能快速判断是客户端过老还是服务端配置问题。第三步用排除法试连。比如 JDBC 场景先在本机用 mysql 命令行客户端连一次如果命令行能连、程序连不上说明问题大概率出在驱动的 URL 参数或版本上而不是数据库端。我测试过最常见的组合Ubuntu 上自带的 mysql-client 8.0 连 MySQL 8.0 服务端完全没问题但如果系统里装的是 mysql-client 5.7哪怕服务端是 8.0也会大概率报错。所以命令行客户端本身的版本升级也值得留意。4.4 针对 caching_sha2_password 的加密传输补充说明最后再补充一个关于 caching_sha2_password 的细节。这个插件在 TCP 连接上第一次握手时需要额外的 RSA 公钥交换过程。如果客户端不支持或者无法完成这个交换同样会导致连接失败。表现出的报错可能是Authentication plugin caching_sha2_password reported error: Authentication requires secure connection。这种场景下有两个可用的处理办法在 JDBC 连接字串里加allowPublicKeyRetrievaltrue允许客户端向服务端请求公钥配合useSSLfalse使用。或者给连接加上 SSL 加密满足安全传输要求。不过上面这两类配置在生产环境再怎么折腾都没升级驱动来得省心。升级组件永远比绕开安全机制更值得推荐。4.5 踩过的坑那些看似有效但后患无穷的偏方网上有一些解法比如把用户的 plugin 直接改掉后再把 MySQL 服务端的skip-grant-tables模式开起来强制重启。我只能说这种方法很危险——skip-grant-tables 意味着所有权限校验直接跳过相当于数据库裸奔。如果你只是为了解决认证报错去开这个开关等于拆了房子补窗户。千万不要在生产环境这么搞。另一个坑是有人在连接参数里把auth_plugin指定为mysql_native_password但服务端用户实际还是新插件这种配置在某些驱动下不一定生效反而可能带来下一次的Access denied报错。优先通过数据库端确认用户的 plugin 状态再决定从客户端还是服务端下手。5. 个人实践经验与一点建议这个报错在我手上出现过好多次最早一次是在一个老 PHP 项目迁移到 MySQL 8.0 时踩到的当时整个团队都很懵。后来慢慢地就有了一个固定的排查节奏先查用户插件再看客户端版本最后根据场景决定改动方向。目前我自己最推荐的组合是服务端 MySQL 8.0 保持默认的 caching_sha2_password 不动客户端统一升级到支持新协议的版本。这样既保障了密码安全又能彻底告别这类兼容问题。Navicat 用 16.x、JDBC 用 mysql-connector-j 8.0.x、Python 用新版本 pymysql 或 mysql-connector-python、Node 用 mysql2基本就一路畅通。如果你实在无法升级客户端才退而求其次去修改用户认证插件。改的时候记得只改具体用户不要全局改配置控制影响范围。最后分享一个小技巧如果你的 MySQL 8.0 已经上线跑了一段时间团队里又存在多个开发环境可以专门创建一个用于老客户端兼容的账号统一设置成 mysql_native_password其余账号保持默认。这样既照顾了开发工具的兼容性又不影响整体安全策略。遇到类似问题复盘时也能快速定位到是哪个账号、哪个环境的配置问题排查起来轻松得多。