MySQL 8.0主从复制报错caching_sha2_password排查与解决
2026/9/17 23:58:42 网站建设 项目流程

很多DBA和运维第一次在MySQL 8.0上搭主从复制时,都会撞上这条报错:

[ERROR] [MY-010584] [Repl] Slave I/O for channel '': error connecting to master 'repl@192.168.x.x:3306' - retry-time: 60 retries: 1 message: Authentication plugin 'caching_sha2_password' reported error: Authentication requires secure connection.

如果你没开SSL,也没做额外配置,八成就是被MySQL 8.0默认的caching_sha2_password认证插件卡住了。这个报错在5.7时代几乎见不到,因为5.7默认还是mysql_native_password,复制用户建好、授权给足、网络通,基本就完事了。到了8.0,事情变了,而且报错信息有歧义,很容易让人误判成"网络不通"或者"密码不对",结果折腾半天方向全错。

这篇文章把这条例报错从原理到实操完整拆一遍,内容包括:这条错误信息到底在说什么、8.0的认证机制为什么会导致复制连不上、完整的排查链路怎么走、以及一份可以直接照抄的主从重建操作清单。不管你是刚接触MySQL的运维新手,还是被这个报错折磨过的老手,这篇都能让你少走弯路。

1. 先搞懂报错:MY-010584 和 Slave I/O 线程的连接流程

1.1 错误码背后的执行单元:I/O线程

MySQL主从复制的架构里,从库上有两个关键线程:I/O线程和SQL线程。I/O线程负责连接主库,把主库binlog拉取到从库的中继日志(relay log);SQL线程负责把中继日志里的SQL在从库上重新执行。两者是串行配合的关系,I/O线程挂了,SQL线程拿不到新数据,主从就断了。

MY-010584这个错误码对应的就是I/O线程连接主库失败。Slave I/O for channel ''里的channel是复制通道,默认是空字符串,如果你配了多源复制,这里会显示具体通道名。

I/O线程的连接流程可以拆成四步:

  1. 解析CHANGE MASTER TO里配置的主库地址、端口、用户名;
  2. 通过TCP建立到主库的网络连接;
  3. 使用复制账号完成MySQL协议层的认证;
  4. 认证通过后,向主库请求binlog坐标,启动拉取。

这四步任何一步出问题,I/O线程都会报错并进入重试循环。报错信息里retry-time: 60 retries: 1的意思是默认每60秒重试一次,当前重试计数到1,这本身不是额外的问题,不用去动重试参数,先把连接失败的原因找到才是正道。

1.2 报错信息里真正有价值的部分

很多人看到报错就慌,其实这条报错信息分三段:第一段是连接目标,第二段是重试机制说明,第三段是message:后面的具体错误原因。前两段只是背景,最后一段才是真正的诊断线索。

比如下面这条:

error connecting to master 'repl@192.168.1.10:3306' - retry-time: 60 retries: 1 message: Authentication plugin 'caching_sha2_password' reported error: Authentication requires secure connection.

重点全在最后:Authentication plugin 'caching_sha2_password' reported error: Authentication requires secure connection.。这说明TCP层已经通了,账号也能找到,卡在认证环节——8.0的caching_sha2_password插件要求走加密连接,或者通过RSA公钥交换密码。

但如果你看到的是下面这样:

message: Access denied for user 'repl'@'192.168.1.20' (using password: YES)

那问题就在账号密码或host白名单上。如果看到的是:

message: Lost connection to MySQL server at 'reading initial communication packet', system error: 95

那大概率是网络层的问题,比如防火墙DROP了端口、主库bind_address限制、或者主库根本没在监听。所以排查的第一步不是去网上搜错误码,而是把message:后面的内容完整读一遍,用它来定位方向。

2. 主从连接失败的11个高频诱因,按概率排序

根据我这些年的经验,MySQL 8.0主从I/O线程连接失败的原因,无外乎下面这些。按出现概率大致排个序:

序号诱因典型报错特征排查难度
1复制账号认证插件与连接方式不匹配Authentication requires secure connection
2账号密码错误Access denied for user
3账号host白名单限制Access denied for user
4防火墙拦截3306端口Lost connection... system error: 95或直接卡死
5主库bind_address只监听了127.0.0.1连接超时或被拒
6复制账号缺少REPLICATION SLAVE权限Access denied或权限不足相关报错
7从库提前执行了START SLAVE但没做CHANGE MASTER TO连接信息不完整或NULL
8server_idserver_uuid冲突报错信息会提示server_uuid重复
9主库skip_name_resolve开启但账号host用的是主机名Access denied
10主库openssl/SSL配置异常SSL相关报错
11主从版本差异过大导致协议不兼容协议握手失败

别急着一个个试,先用手工方式复现连接,一次就能区分出到底是认证问题还是网络问题。具体怎么做下一节讲。

3. MySQL 8.0的"认证插件深坑":为什么复制用户更容易连不上

3.1 8.0默认认证插件的变化

MySQL 5.7及之前版本,默认认证插件是mysql_native_password,密码以哈希形式存储,客户端连接时直接做一次SHA1挑战-响应验证,整个握手过程可以完全走明文TCP,不需要额外的加密通道。

从8.0开始,默认认证插件改成了caching_sha2_password。这个插件安全性更强,但代价是:当连接没有走SSL/TLS时,首次认证需要额外一次RSA公钥交换来加密传输密码。如果客户端不知道服务器RSA公钥,并且连接参数里没指定GET_MASTER_PUBLIC_KEY=1--get-server-public-key,认证就会失败。

你可以在主库上用SQL确认一下默认认证插件:

SHOW VARIABLES LIKE 'default_authentication_plugin';

在8.0.27及之前版本,参数名是default_authentication_plugin,8.0.28开始改名为authentication_policy,用法略有差别:

SHOW VARIABLES LIKE 'authentication_policy';

如果显示caching_sha2_password,那就说明你建复制账号时如果没有显式指定认证插件,建出来的用户用的就是它。

3.2 三种解法对比

解决caching_sha2_password导致的复制连接失败,业内实际用下来有三条路,各有优劣:

方案一:创建复制用户时显式指定mysql_native_password

CREATE USER 'repl'@'192.168.1.%' IDENTIFIED WITH mysql_native_password BY 'your_password'; GRANT REPLICATION SLAVE ON *.* TO 'repl'@'192.168.1.%';

这是最省事的办法,5.7时代的账号怎么建,现在照搬就行。缺点是这个插件在8.0里已标记为废弃,8.4里默认不启用,未来升级时还得改。如果你短期内不升级大版本,这是最稳妥的。

方案二:保持8.0的默认插件,在CHANGE MASTER TO里加公钥获取参数

8.0.23及之后版本的CHANGE MASTER TO支持GET_MASTER_PUBLIC_KEY=1

CHANGE MASTER TO MASTER_HOST='192.168.1.10', MASTER_USER='repl', MASTER_PASSWORD='your_password', MASTER_PORT=3306, GET_MASTER_PUBLIC_KEY=1, MASTER_LOG_FILE='binlog.000003', MASTER_LOG_POS=157;

这样从库在认证前会主动向主库请求RSA公钥,完成密码加密传输。优点是不需要动账号插件,安全等级更高;缺点是RSA公钥交换增加了握手开销,但复制连接是长连接,只在重连时才认证一次,日常开销可以忽略。

方案三:给主库配置SSL并让复制走加密连接

在主库的my.cnf里配置证书,然后在CHANGE MASTER TO里加MASTER_SSL=1

CHANGE MASTER TO MASTER_HOST='192.168.1.10', MASTER_USER='repl', MASTER_PASSWORD='your_password', MASTER_PORT=3306, MASTER_SSL=1, MASTER_LOG_FILE='binlog.000003', MASTER_LOG_POS=157;

这方案最安全,但需要证书体系,内网环境一般没必要额外折腾。

我个人建议:内网环境图省心用方案一,云环境或者安全审计比较严格的环境用方案二。注意,方案二要求两端都是8.0,如果主库是5.7从库是8.0,GET_MASTER_PUBLIC_KEY对5.7主库的mysql_native_password用户无效,这时候直接用方案一就好。

3.3 手工验证认证链路是否打通

不管用哪个方案,配置完之后,先在从库机器上手工连一次主库,直接验证认证链路,比反复看主从状态快得多:

mysql -urepl -p'your_password' -h192.168.1.10 -P3306 --get-server-public-key

如果能正常登录并且执行SHOW DATABASES;有输出,说明账号、密码、权限、认证方式全部没问题。如果报错,错误信息会直接告诉你是认证插件问题还是账号问题。这个验证步骤我每次都做,能省掉大量排查时间。

4. 完整的排查链路:从报错发生到复制恢复

4.1 第一步:拿到完整报错,确认报错段落

在从库执行:

SHOW REPLICA STATUS\G

8.0.22以前版本用SHOW SLAVE STATUS\G,从8.0.22开始官方把"Slave"替换成了"Replica",两种写法在8.0里兼容,但我建议直接用新写法。重点关注这几行:

Slave_IO_Running: Connecting Slave_SQL_Running: Yes Last_IO_Errno: 2061 Last_IO_Error: error connecting to master 'repl@192.168.1.10:3306' - retry-time: 60 retries: 1 message: Authentication plugin 'caching_sha2_password' reported error: Authentication requires secure connection.

Last_IO_Errno是错误码,2059通常跟认证插件有关,2003是连不上网络,1045是访问被拒。先用错误码缩小范围。

4.2 第二步:手工模拟从库连接,区分网络层与认证层

拿到完整报错后,不要急着改配置,先在从库机器上手工执行:

mysql -urepl -p'your_password' -h192.168.1.10 -P3306 --connect-timeout=5

这个命令把TCP连接和MySQL认证一起测了。结果分三种情况:

  • 能登录,说明网络通、账号通。问题大概率出在复制链路的配置细节上,比如CHANGE MASTER TO里密码打错、没有配置GET_MASTER_PUBLIC_KEY等。

  • 报登录被拒,说明账号相关。去主库检查用户是否存在、host白名单是否覆盖了从库IP、密码是否正确。

  • 连不上或超时,说明网络相关。检查防火墙、bind_address、主库端口监听状态。

4.3 第三步:排查账号与host白名单

在主库执行:

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

确认三点:

  1. user是否拼写正确;
  2. host是否覆盖了从库的来源IP(不是从库主机名,而是握手时看到的IP);
  3. plugin是不是caching_sha2_password,如果是,结合第3节的方案处理。

再检查权限:

SHOW GRANTS FOR 'repl'@'192.168.1.%';

必须有REPLICATION SLAVE权限,少了这个权限在部分版本上会报Access denied

顺带说一个容易踩的坑:如果你在创建用户时写的是'repl'@'%',但从库连接时MySQL会按匹配规则先找更精确的条目,如果有一个'repl'@'192.168.1.%'存在而密码不一致,实际用的密码和你想的不一样。这种"隐藏账号"问题最气人,查的时候记得把所有host条目都看一遍。

4.4 第四步:检查主库网络监听与防火墙

这一步适合手工连接超时或报2003错误时做。

在主库确认MySQL监听地址和端口:

SHOW VARIABLES LIKE 'bind_address'; SHOW VARIABLES LIKE 'port';

如果bind_address是127.0.0.1,那非本机连接全部进不来。改成0.0.0.0或具体网卡IP,并确认配置文件里没有别的覆盖项,然后重启MySQL:

systemctl restart mysqld

确认端口在监听:

ss -lntp | grep 3306

正常会看到类似0.0.0.0:3306或具体IP:3306的监听记录。

然后是防火墙,Linux上分两种:

firewall-cmd --list-all

如果firewalld在运行且没放行3306:

firewall-cmd --permanent --add-port=3306/tcp firewall-cmd --reload

如果你用的是云服务器,还得检查安全组是否放行了3306。任何一层拦截都会表现出"连接超时"或"Connection refused"。

还有skip_name_resolve这个变量,开启后MySQL不会对客户端IP做反向DNS解析,账号的host字段必须用IP而不能用主机名。检查方式:

SHOW VARIABLES LIKE 'skip_name_resolve';

开启状态下,如果从库账号的host是'repl'@'db-slave'这种主机名写法,连接会被拒。改成IP段通配。

4.5 第五步:看日志,别只盯着一行报错

从库错误日志的位置:

tail -100 /var/log/mysql/error.log

不同安装方式路径不一样,源码编译默认在数据目录下(通常是/usr/local/mysql/data/里的*.err)。从库日志里通常只记一两条关键信息,真正有价值的有时在主库日志里。如果主库的log_error_verbosity设得够高(2或3),认证失败记录会很详细。

把两边日志的时间戳对齐看,基本能还原完整链路。这套"从库报错+手工连接+主库查账号+两边日志交叉验证"的路径,我每次排查主从问题都是这么走的,从来没失手过。

5. 重建主从复制的一份可复现操作清单

5.1 建复制账号的正确姿势

连接主库执行:

CREATE USER IF NOT EXISTS 'repl'@'192.168.1.%' IDENTIFIED WITH mysql_native_password BY 'StrongPass@2024'; GRANT REPLICATION SLAVE ON *.* TO 'repl'@'192.168.1.%'; FLUSH PRIVILEGES;

注意一点:GRANT REPLICATION SLAVE只需要这个权限就能拉取binlog,不需要给整个库的读权限。网上有些教程让你直接GRANT ALL,这是坏习惯,复制账号权限越小越好。host段写成从库网段(如192.168.1.%),比写'%'安全得多。

5.2 从库的正确配置顺序

在主库执行SHOW MASTER STATUS;(8.4里改为SHOW BINARY LOG STATUS;),拿到当前的binlog文件和位置:

+------------------+----------+--------------+------------------+-------------------+ | File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set | +------------------+----------+--------------+------------------+-------------------+ | binlog.000003 | 157 | | | | +------------------+----------+--------------+------------------+-------------------+

如果你用GTID模式,位置号其实不太关键,但我见过不少用GTID还是会把Position写错的情况。稳妥起见,Position照抄。

然后在从库执行:

STOP REPLICA; CHANGE MASTER TO MASTER_HOST='192.168.1.10', MASTER_USER='repl', MASTER_PASSWORD='StrongPass@2024', MASTER_PORT=3306, MASTER_LOG_FILE='binlog.000003', MASTER_LOG_POS=157, GET_MASTER_PUBLIC_KEY=1; START REPLICA;

STOP REPLICA这步不要省,哪怕刚初始化完的从库也要执行一次,避免前一次实验残留配置。

5.3 验证主从状态各字段的含义

执行完START REPLICA后,等两三秒再查状态:

SHOW REPLICA STATUS\G

关键看这几个字段:

Slave_IO_Running: Yes Slave_SQL_Running: Yes Seconds_Behind_Master: 0 Last_IO_Errno: 0 Last_IO_Error: Last_SQL_Errno: 0 Last_SQL_Error:

Slave_IO_Running: Yes表示I/O线程连上了主库并且正在拉binlog;Slave_SQL_Running: Yes表示SQL线程在正常执行中继日志;Seconds_Behind_Master: 0表示没有延迟。任何一个不是预期值,把对应的Last_*_ErrnoLast_*_Error贴到搜索引擎都比问人快。

注意,Slave_IO_Running刚执行完START REPLICA时可能短暂显示Connecting,如果几秒后变成Yes就正常。如果一直是Connecting,回到第4节的排查链路重新走一遍。

5.4 数据一致性校验

复制链路正常不代表数据没问题。建议在从库执行:

SELECT COUNT(*) FROM your_table;

再在主库执行同样的SQL对比,先粗查几张大表。更严谨的做法是用pt-table-checksum做全量校验,但一般业务先比行数和关键表就够用了。

6. 除了认证插件,还有几个"隐形坑"容易被忽略

6.1 server_uuid重复导致复制异常

克隆虚拟机或从模板恢复实例时,MySQL数据目录下的auto.cnf会带着原来的server_uuid。如果主从两个实例的server_uuid一样,I/O线程连接主库成功后也会被立刻断开,而且报错信息可能被解读成网络问题。

检查方法:

SHOW VARIABLES LIKE 'server_uuid';

两边对比,一样就删掉从库数据目录下的auto.cnf(先停从库),重启MySQL后会自动生成新的UUID。

6.2 从库server_id没改或重复

如果两台机器都是从同一个模板克隆的,my.cnf里的server_id大概率一样。MySQL主从要求每个实例的server_id全局唯一。检查:

SHOW VARIABLES LIKE 'server_id';

修改my.cnf后重启。这个坑和上面server_uuid的区别是:server_uuid在auto.cnf里,server_id在my.cnf里,两者都要检查。

6.3 8.0.23之后的CHANGE MASTER TO语法变化

8.0.23开始,官方把MASTER_*参数改名为SOURCE_*,比如MASTER_HOST对应SOURCE_HOSTMASTER_LOG_FILE对应SOURCE_LOG_FILE。旧的MASTER_*写法在8.0里还能用,但日志里会有一条warning,到了8.4及以后旧语法被移除。新项目直接用新语法:

CHANGE REPLICATION SOURCE TO SOURCE_HOST='192.168.1.10', SOURCE_USER='repl', SOURCE_PASSWORD='StrongPass@2024', SOURCE_PORT=3306, SOURCE_LOG_FILE='binlog.000003', SOURCE_LOG_POS=157, GET_SOURCE_PUBLIC_KEY=1;

对应的启停命令也变成了START REPLICASTOP REPLICA。这些改动不影响5.7老经验迁移,但新环境尽量用新语法写配置。

6.4 主从版本差异过大

MySQL的复制协议大体向后兼容,但8.0和5.7混搭时,有些特性(比如默认字符集、排序规则、JSON实现)会导致SQL线程异常。如果你是从5.7升级到8.0再搭的主从,建议主从版本保持一致,至少在同一个大版本内。像开头搜索词里那种"Django要求8.4但环境只有8.0"的场景,说明业务侧对版本有明确要求,先解决版本匹配,再谈复制。

6.5 从库MySQL服务没起来就开始配置

这种低级错误反而最常见。systemctl status mysqld先确认从库MySQL进程活着,再执行任何复制相关命令。否则CHANGE MASTER TO本身可能成功,START REPLICA也会执行,但状态全是NULL,查半天才发现服务根本没起来。

7. 谈谈我踩过几次坑之后的固定排错顺序

这条例报错我前前后后帮人排查过不下二十次,自己也踩过两回。第一次遇到caching_sha2_password报错时,我第一反应也是去查网络,折腾了半小时才反应过来是8.0的认证机制变化。后来学乖了,只要遇到Authentication plugin字样,先往认证方向想。

我现在搭主从的固定顺序是这样的:先在主库建好复制账号,顺手查一下账号的plugin字段;然后在从库机器上手工mysql -urepl -p... -h...连一次,确认网络和认证都没问题;确认通了再执行CHANGE MASTER TOSTART REPLICA;最后看一眼SHOW REPLICA STATUS确认两个线程都显示Yes

这个顺序看着简单,但它把问题按概率从高到低排列了,每一步都在快速缩小排查范围。手工连接那一步尤其重要,它能一次性区分"能不能连上"和"配没配对"这两个完全不同的层面。

另外一个小建议:复制账号的密码里尽量避免使用@#、空格这些特殊字符,不是不能用,而是在mysql -p'密码'这种命令行场景下容易踩shell转义的坑。真要用,记得单引号包好,或者用MYSQL_PWD环境变量临时指定(注意这招在本机有安全风险,用完记得unset MYSQL_PWD)。

MySQL 8.0的报错信息已经比5.7时代友好不少,但DBA的排查思路还是要成体系。把这篇文章里的排查链路走一遍,绝大多数I/O线程连接失败问题都能在10分钟内定位到根因。别看到报错就重置复制配置重来,先读懂错误码,再动手,效率高得多。

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

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

立即咨询