尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

MySQL 8.0 连接报错 1251:认证插件与客户端兼容性修复

MySQL 8.0 连接报错 1251:认证插件与客户端兼容性修复 如果你最近在连接 MySQL 的时候撞见1251 - Client does not support authentication protocol requested by server这一行红字先别急着怀疑服务器挂了。这个报错我前后在三个不同的环境里踩到过每次排查到最后其实都是同一个问题客户端和服务器之间在用两套完全不同的认证协议打招呼。报错说的是“客户端不支持服务器请求的认证协议”大白话就是两边语言不通。这个错最容易出现在三类场景里老项目连接 MySQL 8.0、旧版图形客户端连接新版本库、以及换库迁移后应用程序突然连不上。新手遇到它往往一头雾水老手如果不熟悉 8.0 的认证机制变更也会绕几圈。这篇文章会把背后的原理拆开讲清楚然后给出从命令行到图形客户端、从 JDBC 到 Docker 部署的完整解决路径直接照着操作就能让服务恢复。1. 认识这个报错1251 到底是啥情况1.1 什么时候会撞上这个错这个报错的触发点很有规律基本集中在客户端连服务器握手的那一瞬间。我遇到的真实案例有几种用 Navicat 11 连 MySQL 8.0 社区版用旧版本 mysql-connector-java 跑 Spring Boot 项目还有一次是运维同学用 5.7 时代惯用的mysql命令行客户端连升级后的 8.0 实例。共同点很明显客户端版本普遍偏老或者驱动库没有跟着升级。MySQL 8.0 正式发布是在 2018 年但国内不少生产环境的客户端工具还是停留在 5.x 时代。旧版客户端去连 8.0 时如果连接账号用的认证插件是新的就会直接收到1251这个错误码。早期很多朋友会用跳过密码验证的方式临时把服务拉起来但那只是绕过问题真要正常连库还是得回来处理认证协议。另外要注意这条报错在不同客户端上显示的文字略有差异但代码1251是固定的。有些工具会显示完整一句有些会显示为Authentication plugin caching_sha2_password cannot be loaded其实背后是同一个坑服务器想让客户端走新的认证流程而客户端不认。1.2 报错信息背后的真正含义把这条报错翻译成人话就是服务器对客户端说“我要用 caching_sha2_password 这个认证插件来验证你可你好像压根不知道这是个啥我没法继续了。”MySQL 在认证环节引入了插件化机制服务器在握手阶段会告诉客户端自己支持的认证方式。客户端接收到服务器的认证请求后需要在本地找到对应的认证插件来完成密码校验。如果客户端不认识双方就只能僵在这儿报错也就随之而来。MySQL 5.7 及更早版本默认用的是mysql_native_password这个插件从 MySQL 4.1 起就没变过几乎所有老客户端都内置了支持。到了 8.0官方把默认认证插件换成了安全性更高的caching_sha2_password问题就出在这儿大量旧客户端根本没有实现这个新插件的支持逻辑。这个报错本身不是数据库坏了也不是密码错了更不是网络不通纯粹是协议版本和认证方式的兼容性问题。理解到这一层后面所有的修复思路其实都会围绕两件事展开要么改账号的认证插件要么升级客户端的认证能力。2. 为什么会这样认证机制到底发生了什么2.1 版本差异8.0 默认认证插件变了要弄明白 1251必须知道 MySQL 8.0 在认证插件上的变化。MySQL 官方的考虑很直接mysql_native_password使用的 SHA-1 密码哈希方案已经服役了十几年安全性跟不上现代数据库的要求。于是 8.0 引入了caching_sha2_password用 SHA-256 级别的算法做密码存储和验证同时在服务端维护一个缓存减少密码验证时的加解密开销。这个设计本身没问题问题在于兼容性。MySQL 8.0 安装完成后默认创建的用户比如 root使用的认证插件就是caching_sha2_password。我测试过即便是全新安装的 8.0.33SELECT user, host, plugin FROM mysql.user;查出来 root 对应的也是 caching_sha2_password。同时要注意MySQL 官网在 8.0 版本还有一个隐藏变化不再默认启用mysql_native_password相关的一些兼容行为需要人为指定。这就导致大量沿用旧习惯的操作开始报错。很多开发者在 5.7 里从来不需要关心认证插件因为老客户端和旧驱动都认 native 协议到了 8.0 不主动处理就必然踩到 1251。2.2 客户端与服务器的握手流程咱们用更贴近实操的方式理解一下这个握手过程。客户端发起连接时服务器先发送握手包包里包含服务器版本、认证插件名、加密种子等信息。客户端读取这些信息后调用自己本地的认证插件用种子和用户密码计算出认证响应再回传给服务器。问题就出在“调用本地认证插件”这一步。老客户端安装到现在代码里只有mysql_native_password的认证模块甚至有些连模块都不完整。当它收到服务器发来的caching_sha2_password插件名称时只能尴尬地回复“我这儿没有这个插件”或者压根不知道该怎么组织认证报文。caching_sha2_password之所以让旧客户端难以支持还有一个原因它要求完整的安全连接。在首次认证时如果客户端没有通过 SSL/TLS 连接服务器需要客户端进行 RSA 公钥加密来传输密码。这一步还需要额外的公钥交换动作对老驱动来说更是不可能完成的任务。2.3 为什么要改成 caching_sha2_password很多人会问既然 mysql_native_password 用得好好的官方为什么要换这不是给自己找事吗从数据库安全的角度看这个问题不难理解。mysql_native_password 的密码哈希算法基于 SHA-1在暴力破解和彩虹表攻击面前已经没有优势。MySQL 8.0 如果想要在合规性和数据安全上往前走必须抛弃老算法。caching_sha2_password 在密码传输上做了很多加固支持完整的 TLS 加密下的快速认证非 TLS 环境下用 RSA 公钥加密保护密码服务端可以缓存认证结果同一用户的重复连接不再重复做代价较高的哈希计算。安全性、性能都比老插件优秀。我个人的态度是不需要因为 1251 报错就骂官方改协议更不建议在生产环境把所有账号一刀切改回老插件。正确的思路是在理解机制的前提下针对不同客户端做不同的适配。老系统临时过渡可以改账号插件新系统应该用支持新插件的客户端和驱动逐步淘汰老协议。3. 解决方案一步步把这个错解决掉3.1 方案一修改已有账号的认证插件最常用这个方案效果最直接适合手头有服务器管理员权限、马上要让老客户端连上来的场景。核心操作就是把客户端正在使用的那个账号从caching_sha2_password改成mysql_native_password。先登录到 MySQL 服务器用 root 或具备修改用户权限的账号执行ALTER USER rootlocalhost IDENTIFIED WITH mysql_native_password BY 你的密码; FLUSH PRIVILEGES;这里rootlocalhost要根据实际情况改成你要修改的用户名和允许登录的主机。比如远程连接用户通常是admin%本地工具连的是rootlocalhost。FLUSH PRIVILEGES在修改用户表权限后执行一下更保险虽然 ALTER USER 本身会即时生效但加这一句能避免某些缓存导致的不确定性。执行完后老客户端再连就不会报 1251 了。需要注意一个坑如果账号原本密码为空直接执行上面的语句会把空密码改成你指定的密码。这个操作会改变登录方式别在生产环境上对着一个维护账号乱改。我一般会先查看当前账号的认证插件和密码策略确认无误再做修改。3.2 方案二新建一个专门给旧客户端用的账号如果不想动 root 这样重要的账号或者生产环境上 root 还要给新客户端用 caching_sha2_password更好的做法是新建一个只给特定应用使用的账号并指定使用老的认证插件。CREATE USER app_user% IDENTIFIED WITH mysql_native_password BY StrongPss2024; GRANT SELECT, INSERT, UPDATE, DELETE ON mydb.* TO app_user%; FLUSH PRIVILEGES;这种做法在兼容性和安全性上权衡得比较好新创建的账号专门服务旧客户端不影响其他账号使用新认证协议。等以后所有客户端升级完毕这个账号可以直接删除不用动全局配置。创建账号时要注意主机范围。本地客户端用localhost远程连接根据实际网段选择%或具体 IP。主机范围定得太宽会增加安全隐患最好精确到最小访问范围。3.3 方案三改回 mysql_native_password 全局默认慎用如果整个 MySQL 实例上连接的全是旧客户端不想一个一个账号去改可以考虑修改全局默认认证插件。在 MySQL 配置文件Linux 通常是/etc/my.cnf或/etc/mysql/my.cnfWindows 是my.ini的[mysqld]段下加上一行[mysqld] default_authentication_pluginmysql_native_password保存配置文件后重启 MySQL 服务。注意这个配置只在 8.0 的早期版本中有效从 MySQL 8.0.34 左右开始官方把参数名改成了default_authentication_plugin但已经标记为废弃后续版本中可能会移除。我在 8.0.36 上实测这个参数还能用但会持续输出 deprecation 警告日志。全局切换的风险也很明显会让所有新建用户默认使用老认证协议整个实例的认证安全性回到 5.7 水平。我通常只在临时迁移环境、短时间内无法升级客户端的场景下才会用这招并且会在迁移完成后尽快改回来、重建账号。3.4 方案四升级/换用支持新协议的客户端从长期角度看治本的方法是让客户端理解caching_sha2_password。这个方案不需要动数据库账号安全性也最好。拿 Java 生态来说mysql-connector-java 5.1.40 以下的版本都不支持 caching_sha2_password升级到 8.0.x 的驱动即可解决。新版驱动不仅支持新插件还能在 URL 中通过allowPublicKeyRetrievaltrue等参数适配非 SSL 场景下的 RSA 公钥获取。图形客户端方面Navicat 16、SQLyog 13.x、DBeaver 新版都支持了 8.0 的认证插件。如果你还在用很老的工作站版本优先升级工具而不是改数据库。命令行客户端也一样使用 MySQL 8.0 自带的mysql客户端去连服务端就是正常握手。如果项目里用的是 PythonPyMySQL 从 0.9.2 开始已支持新的认证插件升级到新版本后连接不会再报错。Node.js 生态则推荐直接用mysql2它对 caching_sha2_password 有很好的支持老mysql包基本已经不维护了。4. 在不同场景下的实操记录4.1 MySQL 8.0 命令行下的完整演示下面是一段完整的命令演示模拟一个运维同学从排查到修复的整个过程。先登录数据库mysql -uroot -p登录后先查一下 root 当前的认证插件SELECT user, host, plugin FROM mysql.user WHERE user root;看到结果里 plugin 是caching_sha2_password就找到问题根源了。接下来执行修改ALTER USER rootlocalhost IDENTIFIED WITH mysql_native_password BY 新的或原样密码; FLUSH PRIVILEGES;修改完再查一遍确认 plugin 变成mysql_native_password。然后退出当前命令行换一个之前报 1251 的老客户端测试连接。这里分享一个小经验如果修改密码时想保持密码不变可以在mysql命令行里先用SELECT CURRENT_USER();确认当前用户再配合ALTER USER ... IDENTIFIED WITH mysql_native_password BY 当前密码;完成切换密码不需要真的改掉。4.2 Workbench、Navicat 等图形工具的处理图形工具连接报 1251处理思路和命令行一致只是不需要打开命令行。你可以先用支持新认证的工具比如新版 Workbench、新版 Navicat登录执行上文里的ALTER USER语句然后再用老工具连接。如果你手上的图形工具本来就是旧版又不想装新工具那就只能在数据库服务器上另想办法。在 Linux 服务器上临时用命令行改账号或者在另一台机器上用新版客户端执行 SQL都是可行的。有朋友问我Navicat 里有没有什么选项可以勾选解决很遗憾认证协议的支持是写死在客户端代码里的旧版没有这个选项只能升级工具或改账号。我见过很多人翻遍了设置菜单也找不到处理入口就是没意识到问题出在客户端版本上。4.3 JDBC/连接池场景怎么配Java 项目遇到这个报错的频率非常高典型异常信息是java.sql.SQLException: Client does not support authentication protocol requested by server; consider upgrading MySQL client。处理分两步。第一步升级 mysql-connector-java。建议使用 8.0.x 的最新版本在 pom.xml 里加上dependency groupIdmysql/groupId artifactIdmysql-connector-java/artifactId version8.0.33/version /dependency第二步在 JDBC URL 中补充必要的连接参数。如果你没有开启 SSL连接串里需要加上allowPublicKeyRetrievaltrue否则新驱动在非 SSL 模式下获取 RSA 公钥时会报另一个错。完整的例子jdbc:mysql://localhost:3306/mydb?useSSLfalseallowPublicKeyRetrievaltrueserverTimezoneAsia/Shanghai连接池也一样阿里 Druid、HikariCP 都支持这种方式。我在给一个老项目升级时发现光换驱动还不够Druid 低版本在初始化连接池时还会主动预连接用的还是旧协议后来把 Druid 版本也升了一级就彻底解决。建议遇到连接池相关报错时驱动和连接池版本一起检查。4.4 Docker 部署 MySQL 后的常见坑Docker 里装 MySQL 8.0 后出现 1251十有八九是因为镜像默认创建的 root 账号用了 caching_sha2_password而宿主机上的旧客户端连不上去。处理方式有两种。第一种在容器启动时通过环境变量指定初始用户的认证方式。在docker run命令中增加docker run -d \ --name mysql8 \ -e MYSQL_ROOT_PASSWORDyourpassword \ -p 3306:3306 \ mysql:8.0第二种进入容器内修改账号插件docker exec -it mysql8 mysql -uroot -p然后执行前面说过的 ALTER USER 语句。如果希望之后新建的数据库账号都默认走老插件可以在容器里的配置文件中加入default_authentication_pluginmysql_native_password。用 Docker Compose 的话可以挂载自定义配置文件到容器内的/etc/mysql/conf.d/目录下。例如新建一个my.cnf写入全局默认认证插件再在 compose 文件中用 volumes 挂载。这个方法适合团队统一默认配置。4.5 老项目迁移到 MySQL 8.0 时要注意的事很多团队从 5.7 迁移到 8.0统一在测试环境爆出大量的 1251。这里特别提醒一句迁移前先把账号体系梳理一遍不要等项目停在那才发现所有应用都连不上。我建议迁移前做三件事。第一整理所有连接这个数据库的应用清单记录每个应用用的连接账号、驱动库版本、客户端工具版本。第二在测试环境创建一套与生产一致的账号逐个应用连接测试把报错的找出来。第三针对报错的应用分两类处理驱动能升级的优先升级驱动驱动不好动比如底层封装了老代码的临时创建 native 账号过渡。迁移过程中如果遇到 root 登录不上的情况可以使用skip-grant-tables临时跳过认证但这招极其危险必须是本地维护且确认没有外部访问的情况下才考虑。处理完认证问题后要第一时间恢复正常认证。5. 常见问题排查实录与避坑经验5.1 修改后依然报错的几个原因有时候明明执行了 ALTER USER再连接还是报同样的错这种情况我总结过几种原因。第一连接串里的账号和你修改的不是同一个。比如你在服务器上把rootlocalhost改了但应用的连接串写的是root%那自然还是要走老插件的缓存或配置。这时候要用SELECT user, host, plugin FROM mysql.user WHERE userroot;把实例里所有同名账号都查出来逐一确认。第二客户端有连接池缓存。应用层的连接池把旧连接缓存着虽然数据库端改了认证方式但已建立的连接不会主动断开。需要重启应用或者等连接池把旧连接回收后再连一次。第三DNS 或 hosts 解析导致连接的服务器不一样。尤其是多实例环境你以为连的是 A 实例实际因为端口映射、内网 DNS 解析到了 B 实例。可以执行SELECT hostname, port;确认当前连接的实例信息。5.2 关于空密码、密码过期和权限的坑MySQL 8.0 的密码策略比 5.7 严格很多默认有密码复杂度要求。如果因为修改认证插件时同时把密码改成了一个过短的密码可能会触发密码校验导致 ALTER USER 执行不成功。另外注意账号的password_expired状态。有些账号创建时设置了密码过期策略连接时服务器会要求必须修改密码后才能继续操作。如果应用是自动化脚本遇到这种账号就会卡住。可以执行SELECT user, host, password_expired FROM mysql.user;如果发现 expired 为 Y用ALTER USER userhost PASSWORD EXPIRE NEVER;取消过期限制。这个操作要结合公司安全策略来做不能乱关。很多朋友遇到坑是因为执行了SET GLOBAL validate_password.policy LOW;把密码策略调低了然后随便设个弱密码结果授权账号可以登录但应用一跑就报权限不足。我把这一点单独提出来是想提醒大家别把认证插件问题和其他权限问题混在一起排查排查时先定位到具体 error message 再动手。5.3 我自己的几条实操心得多说几句个人经验。卡过几次这个报错后我给自己总结了一套处理顺序先查 mysql.user 表确认认证插件再查客户端版本和驱动版本最后再决定改账号还是升级工具。顺序反过来的话容易在不必要的地方折腾半天。关于 DBA 和开发协作这个事我的感受是 1251 这个报错很适合作为一次团队技术对齐的契机。开发反馈连不上DBA 不要只扔一句“升级客户端”就完事而是把服务器端的认证策略、账号规划一起梳理清楚。我见过太多团队在同一问题上反复踩坑本质就是没在这类兼容性问题上建立预案。另外改完账号认证插件后配置文件里如果有skip_name_resolve之类的启用最好顺便确认解析逻辑。我在一个远程连接的场景里遇到过主机映射解析失败导致一直连不上和 1251 叠在一起排查时一度云里雾里。5.4 一张速查表报错信息对照处理方向报错/提示关键内容可能原因优先处理方向1251 Client does not support authentication protocol requested by server旧客户端连 8.0账号用 caching_sha2_password确认 mysql.user 中账号插件执行 ALTER USER 或升级客户端Authentication plugin caching_sha2_password cannot be loaded客户端没有新插件支持升级驱动/图形工具或创建 mysql_native_password 账号Public Key Retrieval is not allowedJDBC 非 SSL 连接需要获取 RSA 公钥JDBC URL 添加 allowPublicKeyRetrievaltrueFailed to create connection连接池初始化失败升级连接池版本、检查驱动版本、确认账号插件Password has been expired账号密码过期使用新密码连接或 ALTER USER PASSWORD EXPIRE NEVERAccess denied for user密码错误或主机白名单不正确检查密码字符串、主机权限、% 与 localhost 的差别这张表我一般放在手册里出现类似报错先对照方向再决定操作步骤。老实说1251这个报错本身并不难难的是不少朋友在报错出现第一瞬间就去翻配置文件、重启数据库完全没有意识到问题只出在握手阶段的认证协议。我前前后后踩过几轮之后学乖了先查账号插件再问客户端版本基本十分钟内就能定位。以后你碰到这个错也可以先这么干省去一大把试错时间。
返回列表