凌晨两点半,告警群突然弹出一条消息:业务库连接失败。登录服务器查日志,密密麻麻全是同一条错误:
code复制ERROR 1524 (HY000): Plugin 'mysql_native_password' is not loaded
当时第一反应是“谁动了插件配置”,排查了一圈才发现根本不是人为误操作,而是MySQL 8.0在特定版本和配置下的一个典型坑。这个报错我前前后后踩过好几次,也帮同事处理过几回,今天索性把它彻底讲透:为什么会触发、有哪些排查链路、各场景下怎么解决,以及怎么绕开它。
1. 报错全貌:ERROR 1524到底在说什么
先把这个错误拆开看。
ERROR 1524是MySQL服务端返回的特定错误码,含义是“请求的插件不存在或未加载”。HY000是ODBC风格的通用错误类别,相当于“一般错误”,它不指向具体模块,但配合1524就能锁定到认证插件问题上。mysql_native_password是MySQL 5.x到8.0早期版本默认使用的认证插件。
这条报错的字面意思是:客户端(或连接请求)要求使用 mysql_native_password 这个插件完成身份认证,但服务端当前并没有加载这个插件。 于是服务端直接拒绝,连接中断。
理解这个东西的关键,在于明白MySQL的认证机制并不是“用户名+密码”这么简单。它实际上是一个插件化的架构:客户端在发起连接时会声明自己要用哪个认证插件,服务端则在自己已加载的插件列表里查找对应插件。如果找不到,它不会退而求其次用别的插件继续认证,而是立刻返回一个明确的错误。这就像你在门禁系统里刷了一张“磁卡”,但读卡器只支持“NFC”,两者不匹配,门就不会开。
mysql_native_password 这个插件在MySQL 8.0之前是绝对主角,但从8.0开始,默认认证插件变成了 caching_sha2_password。官方在8.0里仍然保留了 mysql_native_password 但标记为废弃,到了8.4版本直接默认不启用。很多人在这个过渡期踩坑,就是因为自己的客户端或应用还停留在老思路——总想显式指定 mysql_native_password,结果服务端已经不买账了。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 触发条件盘点:五种常见场景哪种是你遇到的
我在排查和帮别人处理这个报错的过程中,总结出五个最常见的触发场景。你可以对照一下自己属于哪一种。
2.1 MySQL 8.4及以上版本默认禁用了老插件
如果你用的是MySQL 8.4(LTS)或更高的8.x版本,从8.4开始 mysql_native_password 在默认配置下是不加载的。如果应用、旧版客户端或某个历史脚本在连接时指定了这个插件,就会收到1524报错。这是目前遇到最多的情况——不是环境坏了,而是新版本默认行为变了。
2.2 修改用户认证方式时指定了unloaded插件
很多管理操作会涉及这类SQL:
sql复制ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY '密码';
如果当前服务端并没有加载 mysql_native_password 插件,这条语句会直接报1524。就算你只是想修改密码,只要 IDENTIFIED WITH 后面跟了一个未加载的插件名,MySQL就会拒绝执行。
2.3 my.cnf配置文件写入了无效的插件配置
有些人在my.cnf里这样写:
ini复制[mysqld]
default_authentication_plugin=mysql_native_password
这在MySQL 8.0早期版本是生效的。但在8.0.27之后,MySQL逐步废弃这个参数,在8.4中它干脆不生效。如果配置无效但服务端没有报启动错误,服务器仍然启动成功,只是实际默认插件并不是你指定的那个。之后任何试图用老插件连接的用户就会1524。
还有一种情况是配置文件里写了:
ini复制[mysqld]
mysql_native_password=ON
却忘记检查这个参数在当前版本里是否被支持。版本不匹配、参数名拼错、模块路径不对——都会导致插件没有如期加载。
2.4 云数据库实例默认禁用了插件
阿里云RDS、腾讯云、华为云等托管MySQL实例,很多为了安全默认禁用了 mysql_native_password。你的应用如果用了非常老的数据库驱动,驱动会默认要求走老插件认证,云上直接就报1524。这类场景你是碰不到服务器文件系统的,也没法改my.cnf,需要从用户和驱动两方面入手解决。
2.5 Skip Grant Tables状态下执行认证相关操作
如果你用 --skip-grant-tables 模式启动MySQL绕过权限表,然后在“无权限校验”状态下执行 ALTER USER 修改认证插件,操作往往是失败的——因为跳过授权表的同时,插件加载和权限相关的逻辑也不完全正常。此时你遇到的1524可能只是表象,深层原因是启动方式本身就不支持这类操作。
3. 实战排查链路:五步定位问题根源
遇到 Plugin 'mysql_native_password' is not loaded,我建议不要急着改配置,先按下面五步排查,确认根因,再动手。盲目改动容易引发连锁问题。
3.1 第一步:确认MySQL版本
版本决定了你后续所有操作是否适用。执行:
sql复制SELECT VERSION();
- 如果是
8.0.28之前的版本,默认插件就是mysql_native_password,此时报1524基本是插件没加载或配置文件问题。 - 如果是
8.0.28~8.0.36,且没有显式配置默认插件,老插件仍然可用,但已经处于废弃状态。 - 如果是
8.4.x或更高,老插件默认关闭,这是最需要改变策略的情况。
3.2 第二步:查看插件加载状态
用这条SQL确认插件是否在线:
sql复制SELECT PLUGIN_NAME, PLUGIN_STATUS, PLUGIN_LIBRARY, PLUGIN_TYPE
FROM information_schema.PLUGINS
WHERE PLUGIN_NAME = 'mysql_native_password';
或者用管理员登录MySQL后执行 SHOW PLUGINS; 再过滤。如果查询结果为空,说明插件没有安装;如果 PLUGIN_STATUS 显示 DISABLED,说明装了但被关闭。这两种状态报1524的表现非常相似,但处理方法不同。
3.3 第三步:检查全局默认认证插件
sql复制SHOW VARIABLES LIKE 'default_authentication_plugin';
注意,MySQL 8.0.27及以上版本仍能查到这个变量,但它可能已经不再实际生效了。更可靠的方式是查 authentication_policy:
sql复制SHOW VARIABLES LIKE 'authentication_policy';
MySQL 8.0.27引入了 authentication_policy 机制,它比单独的 default_authentication_plugin 更细化,决定了新创建用户的认证组合规则。如果这里的值里不包含 mysql_native_password,那么新建用户或重置用户密码时使用老插件就会失败。
3.4 第四步:查看错误日志
MySQL错误日志里通常会有更细的记录,比如:
code复制[Server] Plugin 'mysql_native_password' is disabled.
这条信息比客户端返回的1524直白得多,能直接告诉你插件是被显式禁用了,还是根本没加载。Linux下默认日志在 /var/log/mysql/error.log,Windows下在当前数据目录下的 .err 文件里。
3.5 第五步:确认当前连接状态
如果你还能通过其他方式连上MySQL(比如使用 caching_sha2_password 等其他插件的账号),优先以管理员身份登录执行查询。如果所有账号都连不上,可能只能在 skip-grant-tables 模式下启动,但务必记得在该模式下不要执行任何认证插件类操作,赶紧排查恢复才是正事。
下面这个表总结一下排查中对症的判断路径:
| 现象 | 可能原因 | 优先验证方式 |
|---|---|---|
| 版本8.4+,插件查询为空 | 默认禁用 | SHOW VARIABLES LIKE 'authentication_policy'; |
| 版本8.0,插件状态为DISABLED | 配置显式禁用或依赖冲突 | 检查my.cnf,查看错误日志 |
| 执行ALTER USER时报错 | 当前用户认证组合不含该插件 | 查询当前用户认证信息 |
| 云端RDS报错 | 云侧安全策略禁用 | 咨询云厂商或改驱动策略 |
| skip-grant-tables下报错 | 启动模式异常 | 关闭该模式正常启动后重试 |
4. 对应解法:三个方向彻底解决问题
排查完原因,就可以选择具体解法了。我按三个方向展开:迁移到新插件、手动加载老插件、修改用户认证配置。你需要根据实际约束来选择。
4.1 方向一:迁移到caching_sha2_password(最推荐)
这是我最推荐的解法。既然MySQL官方已经废弃了 mysql_native_password,老驱动和连接方式迟早要升级,不如一劳永逸。
具体操作如下:
- 使用当前可用账号登录MySQL。
- 确认目标用户当前的认证插件:
sql复制SELECT user, host, plugin FROM mysql.user WHERE user='你的用户名';
- 将用户切换到新的默认插件:
sql复制ALTER USER '你的用户名'@'localhost' IDENTIFIED WITH caching_sha2_password BY '你的新密码';
- 刷新权限:
sql复制FLUSH PRIVILEGES;
如果你的应用使用的驱动比较老(比如PHP 7.x的某些版本、老版本Navicat、Python的旧版PyMySQL),切换后可能遇到 Authentication plugin 'caching_sha2_password' cannot be loaded 之类的报错。这属于驱动端兼容问题,正确做法是升级驱动,而不是改回老插件。
我在一个PHP 7.3的项目上就踩过这个坑:MySQL升到8.0后默认就是 caching_sha2_password,项目里的mysqlnd扩展不支持,直接拒绝连接。后来把PHP从7.3升到7.4,问题消失。所以别只在数据库侧做文章,应用运行时和驱动版本同样关键。
4.2 方向二:重新加载mysql_native_password插件
有些老系统短期内确实没法升级,那只能让服务端把插件加载回来。这个方法分两种情况。
情况A:MySQL 8.0版本(插件文件还在系统里)
先用管理员身份登录,执行:
sql复制INSTALL PLUGIN mysql_native_password SONAME 'mysql_native_password.so';
-- Windows下
INSTALL PLUGIN mysql_native_password SONAME 'mysql_native_password.dll';
执行后验证:
sql复制SELECT PLUGIN_NAME, PLUGIN_STATUS FROM information_schema.PLUGINS WHERE PLUGIN_NAME = 'mysql_native_password';
如果返回 ACTIVE,表示加载成功。
但要注意:INSTALL PLUGIN 方式是动态加载,MySQL重启后不保留。如果你希望永久生效,还得在配置文件中补一段:
ini复制[mysqld]
mysql_native_password=ON
或者:
ini复制[mysqld]
plugin-load-add=mysql_native_password.so
情况B:MySQL 8.4及以上(插件文件可能已移除)
MySQL 8.4默认发布的二进制包中,mysql_native_password 插件文件可能根本不在 plugin_dir 里。你可以先确认:
sql复制SHOW VARIABLES LIKE 'plugin_dir';
然后去对应目录看有没有 mysql_native_password.so 或 .dll 文件。如果文件不存在,单纯的 INSTALL PLUGIN 也会报错。这种情况下要么从相同版本的旧包中拷贝插件文件(不推荐,有兼容风险),要么认真考虑方向一的迁移方案。
提示:在生产环境执行
INSTALL PLUGIN之前,务必先确认当前MySQL版本对应的插件文件路径和版本,不要从不同大版本之间随意拷贝文件。
4.3 方向三:修改用户认证方式时避开指定插件
如果你的场景是“执行ALTER USER时报1524”,但应用其实用不着老插件,那么直接不指定 mysql_native_password 就可以了。
比如原本执行的命令是:
sql复制ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY '123456';
改成:
sql复制ALTER USER 'root'@'localhost' IDENTIFIED BY '123456';
这样MySQL会使用当前默认的认证策略来更新密码。很多时候,应用连不上并不是因为它强制要求老插件,而是某个历史文档或脚本写成那样,实际不需要。改完后再用 caching_sha2_password 连接设备测试,多数情况下就能恢复。
如果你想看一下某个用户当前的认证策略:
sql复制SHOW CREATE USER '用户名'@'host';
返回结果里会有完整的 IDENTIFIED WITH ... 信息,一眼就能看出当前用户绑定的是哪个插件。不要凭记忆乱改,先看清楚现状。
5. 深层机制:为什么MySQL要处理掉mysql_native_password
理解了“怎么解决”,最好再理解一下“为什么”。这对你下次遇到类似报错能不能举一反三非常重要。
5.1 密码哈希算法差异
mysql_native_password 基于SHA1算法,它在认证时会先发送一个随机数challenge,客户端用密码和challenge做SHA1运算返回结果。这个过程存在能被离线字典攻击的隐患——攻击者拦截通信后,可以拿SHA1密文做暴力破解。
caching_sha2_password 基于SHA256,密码在传输中不再直接暴露可离线破解的中间值,安全强度高一个级别。它还有一个缓存机制:同一个用户第一次认证走完整计算,后续认证走会话缓存,性能也不错。
用一个不太恰当的比喻:老插件像是门锁只有一个简单的齿形,配钥匙工具多、容易复制;新插件结构更复杂,就算拿到锁芯也不容易直接做钥匙。
5.2 兼容性代价
MySQL官方在8.0里保留老插件那么久,就是为了给生态迁移时间。但8.4直接默认禁用,说明官方已经明确策略——不再为老算法承担安全债。未来版本大概率彻底移除。
作为使用者,我理解老系统“能跑就不动”的心态。但数据库是基础设施,认证方式的安全性直接影响整个业务的安全底座。如果你还在用老插件,最好列一个升级计划:先查客户端驱动的兼容性矩阵,再分批切换用户认证,避免一次切换影响所有应用。
5.3 一个核心认知
很多人会把“修改用户密码”和“修改用户认证插件”混为一谈。实际上这是两个维度:
- 密码是“你输入的秘密信息”。
- 认证插件是“服务端用什么算法来校验这个秘密信息”。
你在 ALTER USER ... IDENTIFIED WITH 插件名 BY 密码 这个语法里同时做了两件事。如果插件名写错或插件未加载,服务器会拒绝整条语句。所以当报错指向 plugin not loaded 时,未必是密码问题,优先排查插件加载状态。
6. 实操中的避坑记录:三次真实踩坑经历
这里分享几个我在处理这个问题时的实际案例,每一条都对应过真实的生产故障。
6.1 首次踩坑:我以为是配置文件写错,其实是版本特性
有一次在MySQL 8.0.33上给应用新建账号,执行:
sql复制CREATE USER 'app'@'%' IDENTIFIED WITH mysql_native_password BY 'pass';
结果直接1524。我第一反应是 plugin_dir 配置有问题,查了一圈没有问题。后来才想起这个MySQL是编译安装时采用了最小插件集,压根没有包含 mysql_native_password。用 INSTALL PLUGIN 加载后恢复正常。
教训: 版本要确认、插件要查询,不要凭“以前能用”想当然。
6.2 第二次踩坑:云数据库上彻底无法加载老插件
某个客户使用云数据库,应用是用老驱动写的,连接包手写协议,强制走 mysql_native_password,云上控制台报1524。当时想传插件文件到云主机,或者改配置文件,全都没有权限。最终只能将应用侧连接代码改成使用官方支持的新认证方式,还好应用有源码,改动量不大。
教训: 使用云数据库前,先查一下云厂商的插件支持白名单。很多云实例比自建MySQL更严格。
6.3 第三次踩坑:插件虽然加载成功,但认证策略仍报错
有次 SHOW PLUGINS 明明显示 mysql_native_password 是 ACTIVE,可执行 ALTER USER ... IDENTIFIED WITH mysql_native_password BY ... 依然1524。后来发现MySQL 8.0.27之后的 authentication_policy 默认不允许单独使用这个插件作为唯一认证方式。
我在配置里显式添加了:
ini复制[mysqld]
authentication_policy=mysql_native_password
重启后执行同样的 ALTER USER 语句才通过。
教训: 8.0.27版本需要同时关注两个配置:default_authentication_plugin(已废弃但可能仍可显示)和 authentication_policy(实际生效)。只看插件状态不够,还要看全局策略。
7. 最后的建议:先看版本,再看插件,最后改配置
如果你现在正被1524困扰,按下面的顺序操作能最快恢复:
- 用
SELECT VERSION();确认MySQL版本。 - 用
SELECT ... FROM information_schema.PLUGINS确认插件是否加载。 - 用
SHOW CREATE USER '用户名'@'host';确认用户当前的认证方式。 - 判断是“插件未加载”还是“全局策略不允许”,再分别走
INSTALL PLUGIN或ALTER USER的路线。 - 恢复连接后,第一时间更新应用链接字符串,能走新插件就不要回退老插件。
这个错误本质上是MySQL认证体系演进而产生的兼容性摩擦。数据本身没有安全风险,关键是你把认证握手方式和新版本对齐。我的个人倾向一直是:如果不是被老驱动卡死,就别返祖到 mysql_native_password,直接切换到 caching_sha2_password。短痛一次,换来后面几年少踩几个坑,这笔账很划算。
