☰
MySQL 8连接报错1251:认证插件不兼容的解决方案
2026/9/29 16:25:38 网站建设 项目流程

1. 报错复现与根因分析:为什么客户端突然连不上MySQL 8了

先看这个报错本身。完整提示是ERROR 1251 (08004): Client does not support authentication protocol requested by server; consider upgrading MySQL client。出现这个错误时,通常你本地的MySQL客户端版本没问题,甚至命令行工具都能正常连进去,但一换到某个图形工具、旧版驱动或者老项目的配置文件,就直接挂掉。

我第一次踩到这个坑是在帮朋友迁移一套老业务系统的时候。原来跑的是MySQL 5.6,平滑升级到MySQL 8.0之后,命令行连数据库一切正常,但项目里用的老版本JDBC驱动一启动就抛1251,当时还没反应过来是认证方式的锅,一度以为是驱动包和MySQL 8不兼容,换了好几个驱动版本才想到去查认证协议。

这个报错的本质,是服务端和客户端对"密码怎么校验"这件事的算法不一致。MySQL 8.0把默认认证插件从mysql_native_password换成了caching_sha2_password,而很多旧版客户端(比如Navicat 11、MySQL 5.x时代的Connector/J、PHP 7.2以下的mysqli扩展)只实现了前者,不认识后者。服务端一看你手里拿的是过时的握手协议,直接甩出1251让你升级客户端。

换个直白的比喻:老客户端相当于一个只会说方言的访客,MySQL 8.0则是个普通话接待员。方言版的开场白递过去,接待员听不懂,于是把你拦在门外。问题就这么简单,但因为它发生在连接握手阶段,很多人第一反应是IP白名单、端口、防火墙出问题了,反而绕远路。

判断是不是这个问题的策略也很简单,两步:

  1. 在命令行直接敲mysql -u用户名 -p密码 -h主机 -P端口,如果能正常连上,说明网络层和服务本身没问题;
  2. 换一个旧版客户端或旧驱动再连,如果马上冒出1251,基本就可以锁定是认证插件的问题。

接下来要做的就是确认当前用户到底用的是哪个插件,这一步是为后面的修复做铺垫。SQL如下:

SELECT user, host, plugin FROM mysql.user WHERE user = 'root';

看到的结果里,如果plugin列显示的是caching_sha2_password,那就和上面推测完全一致。

2. 三种修复路径的取舍逻辑:改用户、改配置、还是换客户端

解决1251的思路其实分三条线,各有各的适用场景,不建议一上来就乱试,先想清楚你的环境到底以谁为主。

第一条路径:把现有用户的认证插件改回 mysql_native_password。适合的场景是——你有一批老系统、老工具没法升级,必须让它们能连上MySQL 8。操作最快,一条ALTER USER就能生效。缺点是把MySQL 8主推的更强安全特性给降级了,不过这在内网或者开发环境里通常不是大事,业务能跑才是第一位的。

第二条路径:修改MySQL全局默认认证插件。适合的场景是——你要新建一批用户,希望以后创建的用户默认都用老插件,省得每次都手动指定。改的是my.cnf里的default_authentication_plugin参数。注意,这个参数只对"新建的用户"有效,已经存在的用户不受影响,所以你改完配置之后,还得回头处理存量用户。

第三条路径:升级客户端。适合的场景是——你有能力控制客户端版本,或者项目本身值得升级。MySQL 8官方生态里,从MySQL Connector/J 8.0、Python的mysql-connector-python8.0、PHP 7.4以上的mysqli扩展开始,都默认支持caching_sha2_password。这条路相对"最正确",但需要动的面也最广,如果只是临时环境连库,没必要折腾。

我个人的建议是分场景对待:开发机、测试机,直接第一条路径,最快;生产环境有多套老应用引用同一MySQL实例的,优先升级中间层驱动,其次再考虑改全局配置。别在生产环境偷偷用第一条路径把存量用户改成老插件还不留文档记录,等后面运维接手的时候会非常难排查。

3. 首选方案实操:ALTER USER把认证插件改回mysql_native_password

这是网上流传最广、也是实测最稳的一招。执行前先把该备份的备份好,然后按下面的顺序操作。

3.1 用命令行登录MySQL

mysql -u root -p

如果root不允许本地登录,就用能远程登录的管理员账号,比如mysql -u admin -h 127.0.0.1 -P 3306 -p。这一步的核心是"先能进MySQL,才能改MySQL"。

3.2 查看当前用户使用的认证插件

SELECT user, host, plugin FROM mysql.user;

重点看两列:user列确认你要改的是哪个账号,host列决定这条SQL里的'localhost'还是'%'。很多人在这一步踩坑——明明改了用户,却忘了自己的连接实际是从哪个主机来的,导致改完仍然连不上。

host字段的含义是这样的:

host值含义
localhost只允许本机连接
%允许任意主机连接
具体IP(如 192.168.1.10)只允许该IP连接

如果你连接MySQL时的来源匹配的是%,那你ALTER USER的时候也必须用'root'@'%',只改'root'@'localhost'是白搭。

3.3 执行ALTER USER切换认证插件

ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY '你的新密码';

前面'root'@'localhost'按你第2步查到的结果替换,'你的新密码'自己定。注意,MySQL 8默认装了密码强度校验组件,如果密码太简单(比如全是数字、长度不够),这条命令会直接报ERROR 1819 (HY000): Your password does not satisfy the current policy requirements。

不想改复杂密码的,可以把密码强度校验临时降级:

SET GLOBAL validate_password.policy = LOW; SET GLOBAL validate_password.length = 6;

然后重新执行ALTER USER。这招在本地测试环境很实用,生产环境还是老老实实用强密码。

3.4 验证修改结果

SELECT user, host, plugin FROM mysql.user WHERE user = 'root';

确认plugin列变成mysql_native_password之后,用你原来的客户端重新连接一次,1251应该就消失了。

这里有个细节:ALTER USER之后不需要执行FLUSH PRIVILEGES。很多老教程习惯性地在修改权限表之后加一句FLUSH PRIVILEGES,那是给INSERT/UPDATE/DELETE方式直接改mysql.user表用的。ALTER USER是官方接口,内部会自动重载相关缓存。不过多执行一次也没副作用,纯属习惯问题。

3.5 如果你要新建用户并直接指定老插件

CREATE USER 'newuser'@'%' IDENTIFIED WITH mysql_native_password BY '密码'; GRANT ALL PRIVILEGES ON *.* TO 'newuser'@'%'; FLUSH PRIVILEGES;

后面那句FLUSH PRIVILEGES是为了让授权立刻生效,建议保留。这样新建出来的用户默认走mysql_native_password,不会再出现1251。

4. 备选方案:修改my.cnf全局配置,让新用户默认使用老协议

有些场景下,你手头管理的MySQL实例里用户特别多,一个个ALTER USER不现实,或者你希望以后所有新创建的账号都别再用caching_sha2_password,那就要动全局配置。

4.1 找到配置文件位置

Linux环境下通常是/etc/my.cnf或/etc/mysql/my.cnf,也有可能被拆分成/etc/mysql/mysql.conf.d/mysqld.cnf。不确定的话,执行:

mysql --help | grep 'Default options' -A 1

输出里会列出MySQL启动时按顺序读取的配置文件路径,从上到下第一个存在的文件就是它的主配置。

4.2 在[mysqld]段下加参数

[mysqld] default_authentication_plugin = mysql_native_password

注意:必须是[mysqld]段,不是[mysql],不是[client]。写错段会导致参数不生效,而且MySQL在启动时对未知参数一般只报警告不报致命错误,很容易让你误以为改成功了。

4.3 重启MySQL服务

systemctl restart mysqld

或者用service mysql restart,看你的发行版习惯。

4.4 验证默认插件已生效

SHOW VARIABLES LIKE 'default_authentication_plugin';

结果值应该是mysql_native_password。然后新建一个测试用户:

CREATE USER 'tester'@'%' IDENTIFIED BY 'Test123456'; SELECT user, host, plugin FROM mysql.user WHERE user = 'tester';

看到mysql_native_password就说明配置生效了。

这一步最容易忽略的事:老用户还是改不过来。全局配置只影响配置生效后新建的用户,之前已经存在的用户,哪怕你重启MySQL,它的plugin值也不变。所以方案二通常要和方案一配合使用:先全局配置兜底,再用ALTER USER把存量用户逐个转掉。

另外提醒一句,MySQL 8.0的官方文档里已经标记default_authentication_plugin为废弃参数,后续版本可能移除,会用authentication_policy替代。如果你装的是8.0.27以上的版本,改default_authentication_plugin时可能收到弃用警告,不影响老版本兼容性,只是提醒你新版本要换写法。具体语法因版本而异,需要的时候查一下当前版本的官方文档,别照抄老教程。

5. 升级客户端到支持caching_sha2_password的版本

还有一种思路是反向的——既然MySQL 8默认用caching_sha2_password,那干脆让客户端跟上节奏。这种方案最适合"你自己能控制软件栈"的情况,比如新写的项目、可以自由升级的开发工具。

5.1 常见客户端对caching_sha2_password的支持情况

客户端 / 驱动支持版本备注
Navicat12.0+(建议15.x)12以下老版本只支持 mysql_native_password,会报1251
MySQL Workbench8.0+8.0之后基本没问题
DBeaver21.x+新版社区版即可,驱动用 mysql-connector-java 8.0
JDBC (Connector/J)8.0.9+8.0.9开始支持 caching_sha2_password
Python PyMySQL1.0+(0.9.3以上也基本可用)老0.7/0.8版本有兼容问题
PHP mysqliPHP 7.4+7.4之前的mysqlnd不支持
mysql-connector-python8.0+配合MySQL 8使用最稳妥

表格只能做个大致参考,具体到你手里的版本,最快的方式是直接查官方变更日志或试连一次,报错就升级,不报错就继续用。

5.2 连接串层面也需要检查

升级完驱动或客户端之后,连接串里有时还需要显式指定连接属性。比如Java JDBC连接串:

jdbc:mysql://localhost:3306/dbname?user=root&password=xxx&useSSL=false&allowPublicKeyRetrieval=true

这里有两个坑:

  • useSSL=false只在测试环境可用,生产环境建议启用SSL或用SSH隧道;
  • allowPublicKeyRetrieval=true是专门配合caching_sha2_password使用的。因为这种插件在非SSL连接下第一次认证时需要从服务端获取公钥,默认允许自动获取公钥的选项是关闭的,不打开就会报错。这个问题经常和1251一起出现,如果你改完认证插件后其他错误消失、却冒出来一个新错误,多半就是它在作怪。

之前有个读者私信我,说按网上的教程把useSSL=false加进去就好,结果加完之后又报Public Key Retrieval is not allowed,其实就是allowPublicKeyRetrieval没开。

5.3 升级客户端之后的平滑过渡

这里给个实操过程。以Java项目为例:

  1. 确认pom.xml里的依赖版本,把mysql-connector-java从5.x升到8.0.x;
  2. 修改连接串,加上allowPublicKeyRetrieval=true;
  3. 启动项目,观察日志里是否还有认证相关报错;
  4. 验证查询、事务、批量插入等核心操作都正常。

如果是Python项目,把PyMySQL升到1.0以上,代码层面基本不用改,连接参数里保持现有的host/port/user/password就行。

一句话总结第5节的核心:能升级客户端的地方,尽量升级,不要图省事把所有用户都钉在老的认证插件上。安全这种东西,内网感觉不出来,等真要面对外网攻击或等保检查的时候,想改回来反而麻烦。

6. 真正排查一次1251:完整的故障处理链路复盘

只给方案不给过程,读者遇到变种问题还是会懵。我完整复盘一次处理1251的排查链路,方便你对照着复现思路。

6.1 第1步:先确定不是网络和IP授权问题

场景还原:一台新装的MySQL 8.0.36,运行在云服务器上。本地Navicat连接报1251。

我先执行了ping和端口检查:

telnet 云服务器IP 3306

端口通,说明网络层没问题。然后用命令行登录MySQL,确认服务端正常:

mysql -u root -h 云服务器IP -p

这里我要强调一个细节:很多云服务器上的MySQL会默认禁止root远程登录,或者只监听127.0.0.1。如果你命令行登录都报Access denied或者Can't connect,那要先处理远程授权和监听地址,1251只是表象之一。

6.2 第2步:核对用户表里client使用的主机范围

这一步我通常会多敲几条SQL,把信息查全:

SELECT user, host, plugin FROM mysql.user;

查到root的host有好几条记录,有'localhost'、有'%'、还有一个具体IP。而Navicat实际连接时用的来源是某云服务器的内网IP,所以真正匹配的是'root'@'%'那条记录。如果只看'root'@'localhost'的plugin,就可能误判。

6.3 第3步:区分1251和2059

这里补充一个高频混淆点:MySQL 8连接时还有另一个类似的报错2059,提示是Authentication plugin 'caching_sha2_password' cannot be loaded。这两个一个侧重"客户端不支持服务端请求的协议"(1251),一个侧重"客户端负载不了服务端的插件"(2059),但它们指向的都是同一个根因——认证插件不兼容。

如果你遇到的报错编号是2059,修复方法和1251完全一样:要么改用户插件,要么升级客户端。遇到2059时,甚至还可以用navicat的高版本直接绕过,因为新版的Navicat自带caching_sha2_password支持。

6.4 第4步:处理存量用户

确认是'root'@'%'的问题之后,我执行了:

ALTER USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY '强密码';

执行完没有立刻验证成功与否,而是再做了一次完整查询:

SELECT user, host, plugin FROM mysql.user;

确认'root'@'%'的plugin已经是mysql_native_password,然后再从Navicat重连,成功。

6.5 第5步:长期维护的兜底配置

因为这台服务器后续还要给多个项目开账号,我顺手把全局默认插件也改掉了,省得每次创建新用户都要手动指定。步骤就是第4节说的那套,改my.cnf、重启、验证。

整体排查链路可以用一句话概括:网络通不通 -> 服务端能不能登 -> 用户表host是否匹配 -> 插件是否兼容 -> 按场景选修复方案。这条链路走下来,不管是1251、2059、还是Public Key Retrieval is not allowed,都不会让你慌。

7. 实操中的那些额外坑:密码策略、SSL连接、Navicat缓存

7.1 密码策略拦路

ALTER USER执行后报1819的坑,前面提过一次,这里展开说一下。MySQL 8默认的密码校验规则是级别MEDIUM,要求密码至少8位、包含大小写字母和数字,特殊字符可选。如果你设置的密码不满足规则,修改操作会被拒绝。

想临时降低策略的话:

SET GLOBAL validate_password.policy = LOW; SET GLOBAL validate_password.length = 6;

这两个是全局变量,修改后立即生效,但你不需要重启MySQL。如果是生产环境,我建议保持默认策略,没必要为了修复认证兼容问题额外降低安全门槛。开发环境随意。

还有一个更小的坑:如果MySQL是5.7版本,变量名是validate_password_policy,用的是单词间的下划线;MySQL 8的validate_password组件改成了validate_password.policy,中间是点号。网上搜到的资料新旧混杂,注意区分你装的版本,直接复制5.7的写法到8.0身上会报Unknown system variable。

7.2 SSL连接错误和1251容易被混为一谈

很多人在连接MySQL 8时同时遇到过1251和SSL相关报错,其实这俩经常是连体婴儿。caching_sha2_password在非SSL连接下需要额外的公钥交换步骤,而SSL连接如果证书或useSSL配置不对,又会先报SSL错误,把认证问题盖住。

我建议的处理顺序是先关SSL测试:

mysql -u root -h 127.0.0.1 -P 3306 -p --ssl-mode=DISABLED

如果此时能连上,说明认证插件没问题,真正的坑在SSL配置。然后再回头单独处理SSL——要么导入证书做双向认证,要么确认连接串里useSSL=false的合理性。

从热搜里也能看到,mysql ssl连接错误和mysql设置默认值为0这类问题经常出现在同一批搜索记录里,就是因为MySQL 8的默认行为变化和旧客户端习惯冲突太多,1213、1251、2059轮着来。

7.3 Navicat的缓存导致"改完还报错"

改完认证插件后,你兴冲冲地打开Navicat重连,结果还是1251——这种情况并不少见,多半是Navicat自己的连接缓存和密码缓存没刷新。

处理办法也简单:

  1. 断开当前连接;
  2. 在Navicat连接管理里删掉这个连接配置,重新填一次;
  3. 重启Navicat(不是断开重连,是彻底退出)。

有些版本还会把老密码缓存在系统密钥链里,重启大法基本都能覆盖。

7.4 Docker安装MySQL时的注意事项

如果MySQL是Docker容器跑的,比如配置里写的是docker run -e MYSQL_ROOT_PASSWORD=xxx mysql:8.0,那么修改认证插件时要注意:

  • ALTER USER可以直接在容器里执行,不受影响;
  • 修改my.cnf需要docker exec进容器操作,或者更规范的做法是启动时挂载配置目录/etc/mysql/conf.d,把配置文件放到宿主机再映射进去;
  • 容器重建后,你所有对认证插件的修改都会丢失,除非做了数据目录的volume持久化。

一个推荐的启动参数组合:

docker run -d \ --name mysql8 \ -p 3306:3306 \ -v /data/mysql/conf:/etc/mysql/conf.d \ -v /data/mysql/data:/var/lib/mysql \ -e MYSQL_ROOT_PASSWORD=你的密码 \ mysql:8.0

之后要改全局配置的话,在宿主机编辑/data/mysql/conf/my.cnf,重启容器即可。

8. 排查1251问题的一种习惯性思路:先看全局,再动用户

接触这个报错多了之后,我慢慢形成了一种自己的排查习惯,不是死记硬背命令,而是按"服务端状态 -> 客户端支持度 -> 用户细节 -> 最小改动"的顺序来。

最小改动这条原则特别重要——能用一条ALTER USER解决的,绝不改my.cnf再重启服务;能升级一个客户端解决的,绝不批量改动存量用户。1251这种问题看上去只是认证方式不匹配,但它背后牵扯到的是客户端生态的碎片化程度。你永远不知道哪个角落里还有一台老服务器、一个老调度脚本、一个封存在项目里的老驱动在默默连接同一个MySQL实例,改动越激进,爆炸半径越大。

打个比方,这就像你给老小区换智能门锁。门锁本身没问题,安全等级更高,但要是小区里有几个老人还不会用指纹和密码,你就得留一把机械钥匙的备用方案。mysql_native_password就是那把机械钥匙,你可以保留它,但别把它设成所有人都默认使用的方案。

如果你正被1251困扰,我建议按下面这个顺序快速自救:

  1. 确认能进命令行,把mysql.user表里所有用户的plugin列查出来;
  2. 确认你客户端连的是localhost还是%,找准目标用户;
  3. 先用ALTER USER解决当前最紧急的登录问题,让业务先跑起来;
  4. 有空了再评估要不要升级客户端、要不要改全局配置,一步一步来,不要想着一口气把所有兼容问题都处理完。

MySQL 9.0已经在路上了,它的认证插件生态会更加收敛,但老项目、老工具不会一夜之间消失。1251这个报错在某种程度上是"新旧交替"的正常阵痛。把原理弄明白,把排查链路跑顺,不管是1251还是2059,都只是纸老虎。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询