1. 先看清这个错误:mysql_native_password 到底是什么
1.1 一次升级后突然连不上数据库
先给你还原一个我前几天在群里看到的真实场景:某团队把 MySQL 从 5.7 升级到 8.4,升级完成后,老业务系统开始报错,应用日志里反复出现类似这样的内容:
ERROR 1524 (HY000): Plugin 'mysql_native_password' is not loaded更早的版本里,这个错误还会以另一种面貌出现:
Access denied for user 'app'@'localhost' (using password: YES)但后面跟着一句不起眼的注释:Authentication plugin 'mysql_native_password' cannot be loaded。很多 DBA 看到第一反应是“密码错了?账号被锁了?权限没了?”结果挨个排查一圈,密码没错、网络正常、账号存在,最后才发现问题出在认证插件上。
这个错误的核心含义其实非常直白:客户端(或连接驱动)试图用mysql_native_password这种认证方式去连 MySQL,但服务端当前并没有加载这个插件,于是直接告诉客户端“这个插件我没加载,不认识”。对 MySQL 8.0 之前的用户来说,mysql_native_password是默认认证方式,升级后突然不认识了,第一反应肯定是懵的。
1.2 认证插件与 “not loaded” 的关联
要理解这个问题,得先搞明白 MySQL 的认证插件机制。简单说,登录 MySQL 时,客户端和服务端要共同决定“用什么算法验证用户密码”。MySQL 从 5.5 开始就把认证方式插件化了,mysql_native_password是使用了十几年的老牌插件,它用 SHA1 做一次哈希加随机盐的挑战应答验证,兼容性极广,几乎所有编程语言的数据库驱动都支持它。
但老并不等于好。MySQL 官方从 8.0 开始引入caching_sha2_password,并在 8.0 里把默认认证插件从mysql_native_password改成了caching_sha2_password。这就是“历史断裂”的起点。更要命的是,官方一直在推动废弃旧插件:8.0.34 版本开始,MySQL 在启动时打印弃用警告;到 8.4 版本,mysql_native_password插件默认不再加载,除非你在配置文件里显式开启。也就是说,你明明没有做任何配置变更,仅仅是升级了数据库,旧插件就从“默认可用”变成了“默认禁用”。
Plugin 'mysql_native_password' is not loaded这个报错,本质上就是服务端在认证初始化阶段没找到这个插件。可能原因有三类:
- 插件文件缺失:安装精简版或从二进制包解压时,
mysql_native_password.so(Linux)或mysql_native_password.dll(Windows)没有随包分发。这种情况比较少见,但确实存在。 - 配置文件显式关闭或未开启:MySQL 8.4 以上版本,如果配置里没有写
mysql_native_password=ON,插件默认不加载。 - 插件加载失败:文件存在,但文件权限不对、依赖的动态库缺失,或者 MySQL 进程启动时工作目录/
plugin_dir路径有问题,也会导致插件加载失败,进而报出这个错误。
理解了这个机制,你就知道这不是“数据库坏了”,也不是“密码错了”,而是“认证方式对不上了”。接下来我们要做的,是快速定位到底哪一环出了问题,然后对应解决。
2. 开始排查:三步定位是加载问题还是配置问题
2.1 第一步:直接查看插件是否真的没加载
先用管理员账号连上 MySQL(如果还能连上的话)。MySQL 提供了非常直观的查询方式:
SHOW PLUGINS;输出结果里会有一行类似:
mysql_native_password | ACTIVE | AUTHENTICATION | mysql_native_password.so | GPL如果你看不到mysql_native_password这一行,说明当前实例里确实没有加载这个插件。更精确的查询可以走information_schema:
SELECT PLUGIN_NAME, PLUGIN_STATUS, PLUGIN_TYPE FROM information_schema.PLUGINS WHERE PLUGIN_TYPE = 'AUTHENTICATION';这个查询会把所有认证插件都列出来。如果PLUGIN_STATUS是DISABLED或DELETED,那就是加载了但被禁用;如果查询结果里压根没有,那就是根本没加载。这一步能立刻把问题范围缩小到“配置问题”还是“插件缺失问题”。
2.2 第二步:确认当前默认认证策略
MySQL 8.0 里常用这个变量:
SHOW VARIABLES LIKE 'default_authentication_plugin';到了 8.0.27 之后,MySQL 引入了一个更灵活的authentication_policy系统变量,它可以指定优先使用哪个认证插件、允许哪些后备插件。在 8.4 里你可能会看到这样:
SHOW VARIABLES LIKE 'authentication_policy';如果这里的值只包含caching_sha2_password,而列表中又没有mysql_native_password,那么在创建用户或者修改密码时,如果语句里显式指定了IDENTIFIED WITH mysql_native_password,就会直接触发 “not loaded” 错误。这个信息非常关键,它会直接影响后面选择哪种解决方案。
2.3 第三步:翻错误日志和启动参数
如果上面的查询都执行不了(比如你连管理员都登不进去,因为服务进程根本没起来),那就去看 MySQL 错误日志。日志通常位于数据目录下,名字一般叫<hostname>.err,也可能被你配置到其他地方。用 grep 搜一下:
grep -i "native_password" /var/log/mysql/error.log常见的关键字包括:
[ERROR] Plugin 'mysql_native_password' is not loaded [Warning] 'mysql_native_password' is deprecated and will be removed in a future release. [ERROR] Can't open shared library 'mysql_native_password.so' (errno: 2 ...)如果你看到Can't open shared library,那基本可以断定是插件文件本身缺失,或者动态库路径有问题。接着再检查 MySQL 启动时的plugin_dir变量:
SHOW VARIABLES LIKE 'plugin_dir';默认是 MySQL 安装目录下的lib/plugin,如果这个目录里确实没有mysql_native_password.so,说明安装包不完整,或者有人动了文件。顺便检查目录权限:
ls -l /usr/lib/mysql/plugin/正常情况下权限至少是755,文件归属应该是mysql:mysql。如果文件存在但权限是640或者归属异常,也会导致 MySQL 进程加载失败,这个细节很容易被忽略。
这三步走完,基本就能确定是以下三种情况之一:
- 插件文件缺失或加载失败;
- 插件文件正常,但配置没有启用;
- 插件启用且正常,但你的业务账号仍然指定了旧的认证方式,导致认证失败。
搞清楚是哪种情况,再去选择解决方案,就不会瞎折腾。
3. 五种解决方案实操:从应急到根治
3.1 方案A:在配置文件里显式启用插件(适合控制服务器的运维同学)
如果你用的是 MySQL 8.4 或更高版本,最直接的解决方式就是在my.cnf/my.ini的[mysqld]段下加上:
[mysqld] mysql_native_password=ON然后重启 MySQL 服务。重启后可以再用SHOW PLUGINS;验证。这个参数在 MySQL 8.4 中依然有效,但注意,它的含义是“允许加载 mysql_native_password 插件”,并不会自动把现有账号的认证方式改过来。你只是给老客户端开了个“兼容门”,让老驱动能继续用旧插件认证。
这里有一个很重要的坑:MySQL 8.0 早期版本里并没有mysql_native_password这个系统变量(至少在 8.0.34 之前插件是默认启用的,你不需要设置它)。如果你在 8.0.20 之类的版本里强行在配置里写mysql_native_password=ON,MySQL 可能无法识别这个变量,启动直接失败,错误日志里会提示Unknown variable 'mysql_native_password'。所以,加配置之前一定要确认版本,千万别莽。
3.2 方案B:动态加载插件(适合临时应急、不方便重启的集群)
如果你不想重启数据库,可以试试在 MySQL 会话里直接安装插件:
INSTALL PLUGIN mysql_native_password SONAME 'mysql_native_password.so';执行成功后,再查看插件状态就能看到它了。注意两点:
SONAME后面的文件名要根据你的操作系统变化。Linux 下一般是mysql_native_password.so,Windows 下是mysql_native_password.dll,macOS 下也是.so后缀,但路径可能不同。- 动态安装插件需要
INSERT权限,并且要求插件文件在plugin_dir下。如果文件不存在,这条语句会报错,错误信息里会带着具体路径,方便你进一步定位。
动态加载的缺点是:实例重启后,插件不会自动加载。如果你用的是 MySQL 8.4,重启后依然会回到“没加载”的状态。所以这只能作为临时方案,长期还是要落到配置文件里。
3.3 方案C:把现有账号改成 caching_sha2_password(推荐,向新认证靠拢)
站在长远角度看,mysql_native_password已经是明日黄花,官方后续版本大概率彻底移除。与其一直开兼容模式,不如趁这个报错出现,把账号的认证方式升级到caching_sha2_password。操作也不复杂,管理员账号执行:
ALTER USER 'app'@'%' IDENTIFIED WITH caching_sha2_password BY '你的密码';这个语句会把app账号的认证插件改掉,密码也会重置。注意,BY '你的密码'是必填的,不能省略。如果你想保留现有密码,也可以先用查询拿到当前哈希再放回去,但操作复杂且容易出错,不如直接重置一个临时密码,然后让业务侧修改连接配置里的密码。
改完之后,还要处理客户端驱动。如果用的是老版本的 JDBC 驱动(比如 MySQL Connector/J 5.1.x),默认可能不支持caching_sha2_password,需要升级驱动,或者在 JDBC URL 里加上参数:
jdbc:mysql://localhost:3306/db?allowPublicKeyRetrieval=true&useSSL=false项目是 Python 的话,确保pymysql或mysql-connector-python是新版本;如果是 PHP 的mysqli扩展,也需要确认 PHP 版本和编译参数。这一步往往是业务方容易忽略的雷区,我在实际处理时经常遇到“数据库改好了,应用还是连不上”,一查发现应用服务器上的驱动还是五年前的。
3.4 方案D:调整全局 authentication_policy,把 native_password 加进白名单
MySQL 8.0.27 之后,官方推荐使用authentication_policy而不是老的default_authentication_plugin来控制认证策略。它的语法比较复杂,可以指定多个插件:
SET GLOBAL authentication_policy = 'caching_sha2_password,mysql_native_password';或者在配置文件里写:
[mysqld] authentication_policy = 'caching_sha2_password,mysql_native_password'这样做的效果是:MySQL 在创建新用户时,默认认证方式仍优先使用caching_sha2_password,但同时也允许mysql_native_password作为后备认证方式。如果你创建用户时写了IDENTIFIED WITH mysql_native_password这种语句,就不会再报 not loaded 了。
但要注意,authentication_policy不是在所有版本中都支持同样的格式。8.0.27 到 8.0.33 之间的版本,空位的含义很复杂,比如authentication_policy='caching_sha2_password,,'这样的写法有特殊含义。在 8.4 里,格式又有些变化。所以使用前最好先看一下当前值的结构:
SHOW VARIABLES LIKE 'authentication_policy';如果已经有值了,再在这个基础上追加,别直接覆盖,否则可能把已有的认证策略搞乱。稳妥起见,这个方法我更推荐在测试环境先验证,再上生产。
3.5 方案E:只给个别账号开旧认证,不做全局修改
如果整个系统里只有一两个老客户端实在改不了(比如某个供应商的商业软件,驱动已经停止维护),那就没必要全局开启旧插件,只针对这些账号进行修改即可。前提是插件本身已经加载,然后执行:
ALTER USER 'legacy_app'@'%' IDENTIFIED WITH mysql_native_password BY '密码';这样其他账号继续用新的caching_sha2_password,只有这个老账号走旧认证。在 MySQL 8.4 环境下,你依然需要在配置里开启mysql_native_password=ON,否则插件没加载,这句ALTER USER还是会报 not loaded。
这种方式的好处是影响面最小,坏处是这个账号的密码哈希安全性弱一些。mysql_native_password使用的是 SHA1,在暴力破解面前不如新的 SHA256 派生算法。所以尽量限制这个账号的权限,只给它访问最少需要的库表。
4. 避坑清单与常见问题速查
4.1 升级后插件状态变化的三个坑
第一个坑,就是升级 MySQL 大版本前没检查插件状态。实际操作中,我只见过少数团队会在升级前执行SHOW PLUGINS比对插件列表。多数人都是升完之后应用一挂才开始排查。如果你正在计划升级,建议提前在测试环境跑一遍这个查询,把 5.7 和 8.x 的认证插件列个对比表,心里有数。
第二个坑,是只改配置不重启。很多人遇到这个问题后,在网上搜到“在 my.cnf 里加一行 mysql_native_password=ON”,然后就改完了,结果半天还是连不上。原因是 MySQL 的插件加载是启动时发生的,改配置文件必须重启实例才生效。对于有主从复制、高可用切换的集群来说,重启可不是小事,要记得计划维护窗口。
第三个坑,是动态加载插件后忘记写配置。我在生产库上曾经用INSTALL PLUGIN临时解决了问题,结果下个月机房断电重启,应用又开始报同样的错误。当时排查了半天才想起来,配置里没有加持久化设置。所以用INSTALL PLUGIN临时救急之后,务必把对应配置同步写入my.cnf,并且注释写明原因。
4.2 常见问题速查表
| 错误信息 | 可能原因 | 处理办法 |
|---|---|---|
Plugin 'mysql_native_password' is not loaded | 插件未加载或已禁用 | SHOW PLUGINS确认;配置mysql_native_password=ON或INSTALL PLUGIN加载 |
Authentication plugin 'mysql_native_password' cannot be loaded | 驱动或连接器不兼容 | 升级客户端/驱动;或把账号改为caching_sha2_password |
Can't open shared library 'mysql_native_password.so' | 插件文件缺失或权限错误 | 检查plugin_dir下文件是否存在、权限是否正确,重新安装或拷贝插件文件 |
Unknown variable 'mysql_native_password' | 版本过旧,不支持该配置项 | 确认 MySQL 版本,改用authentication_policy或直接使用INSTALL PLUGIN |
ERROR 1524 (HY000): Plugin 'mysql_native_password' is not loaded | CREATE/ALTER USER时显式指定了未加载插件 | 先加载插件;或把语句改成IDENTIFIED WITH caching_sha2_password |
4.3 其他 “plugin XX is not loaded” 类错误的联想
写到这里,顺便提一嘴。这类 “plugin is not loaded” 的报错,不只是 MySQL 里会遇到。比如 Qt 的qt.qpa.plugin: Could not find the Qt platform plugin "linuxfb",本质是插件目录缺失或者加载路径不对;再比如有些工具加载dsh plugin失败,通常是插件目录和配置文件路径没对齐。处理思路大同小异:先确认插件文件在不在,再确认路径对不对,最后确认依赖库是否齐全。这些经验是通用的。
但说实话,MySQL 这个报错最让人头疼的不是技术难度,而是信息不对称——DBA 认为是应用的问题,应用认为是数据库的问题,双方来回拉扯。我在实际处理这类问题时,都会建议双方先坐下来,把下面三个信息拉齐:
- 数据库版本和
SHOW PLUGINS输出; - 应用服务器的数据库驱动版本;
- 完整的连接串。
只要这三样对齐,90% 的认证插件问题都能在五分钟内定位。
5. 实操经验:我在处理这个报错时的三个习惯
最后分享几个我自己的实操习惯。这些习惯不一定写在官方文档里,但确实能帮你节省大量时间。
第一个习惯,是维护一个“认证方式变更记录”。任何一次大版本升级,我都会先在变更记录里写明升级前后默认认证插件的变化。比如从 5.7 升到 8.0,默认认证插件从mysql_native_password变成caching_sha2_password,这是个必读事项。有了这个记录,再遇到应用连不上,你一眼就能猜到问题根源,而不是从零开始查。
第二个习惯,是尽量用连接串显式指定认证插件。像 MySQL Workbench、DataGrip 这类图形工具,都可以在连接配置里选择认证方式。如果你用的是命令行客户端,也可以在启动参数里加:
mysql --default-auth=mysql_native_password -u app -p--default-auth参数能强制客户端使用指定插件,方便测试服务端到底支持哪些插件。如果强制指定后提示 not loaded,问题一定在服务端;如果不指定能正常连,说明是客户端默认选择了一个服务端不认的插件。
第三个习惯,是“改完必验证”。不管用了方案 A 还是方案 C,最后都别只看SHOW PLUGINS就完事。想办法用老客户端的实际连接方式测一下:
mysql -u legacy -p -h 127.0.0.1 -P 3306 testdb如果命令行能连上,但应用还是报错,那问题大概率在应用服务器的连接串或驱动上。这个时候别死磕数据库,去看看应用的数据库连接池配置,尤其是 JDBC URL 里有没有写死authenticationPlugins之类的参数。
我遇到过最离谱的一个坑是,连接串里写了一个自定义的认证插件类名,但这个类在应用里根本不存在,导致启动时直接抛 “Plugin not loaded”。这类问题跟 MySQL 服务端一点关系都没有,纯粹是配置错误。所以碰到这个报错,也要敢于怀疑自己这边的配置,而不是第一反应就去重启数据库。