mysql 5.7→8.0复制可行而反向失败,因8.0能向下兼容解析5.7的row binlog、gtid及事件结构,但5.7无法识别8.0新增的系统表、caching_sha2_password认证插件及原子ddl日志格式,导致报错中断。

MySQL 5.7 主库 → MySQL 8.0 从库可以平滑配置,但反过来绝对不行;切换本身不依赖版本号自动适配,必须手动校验位点、关闭旧主写入、并确保新主已完全同步原主的最后变更。
为什么 MySQL 5.7 → 8.0 复制能跑通,而反向会失败
MySQL 8.0 的复制线程能解析 5.7 生成的 ROW 格式 binlog,包括 GTID(如果启用)、事件结构和数据类型映射;但 5.7 无法识别 8.0 新增的系统表结构(如 mysql.role_edges)、默认密码认证插件(caching_sha2_password)、或 8.0 引入的 DDL 原子性日志格式。一旦 8.0 主库产生这类事件,5.7 从库会报错中断:Unknown system table 或 Unsupported authentication plugin。
所以迁移方向必须单向:旧主(5.7)→ 新从(8.0),后续再将该 8.0 实例提升为新主。
- 主库版本 ≤ 从库版本是硬性前提,不是“建议”
- 即使只用
mysqldump导出导入,也要检查CREATE TABLE中是否含 8.0 特有语法(如JSON_VALID()函数调用) - 若原主库启用了
binlog_checksum = CRC32(5.6.6+ 默认),8.0 从库必须保持兼容,不能设为NONE,否则START SLAVE会拒绝启动
配置时必须改掉的三个关键参数
仅修改 my.cnf 不够,有些配置项在运行时生效但会被忽略,必须显式确认:
-
server-id:新从库(8.0)的server-id必须与原主库(5.7)和其他所有节点不同,且不能为 0;可在启动后执行SELECT @@server_id;验证 -
binlog_format:原主库必须是ROW(5.7 默认已是),8.0 从库无需开启log-bin,但若要支持级联复制或后续升主,建议开启并设为ROW -
replicate_ignore_db/replicate_do_db:避免使用这些库级过滤规则,它们在跨版本下行为不一致;改用replicate_rewrite_db或直接在应用层控制同步范围
特别注意:MySQL 8.0 默认启用 skip_log_bin,如果从库意外开启了 binlog 但没配 server-id,会导致复制线程拒绝连接主库——错误信息为:ERROR 2003 (HY000): Can't connect to MySQL server,实际是权限/配置校验失败,不是网络问题。
切换前最易被跳过的三步验证
很多人看到 Seconds_Behind_Master = 0 就认为可以切了,其实远远不够:
- 执行
pt-table-checksum对比主从表行数和校验和,尤其关注大表(如订单、日志)——Seconds_Behind_Master = 0只说明 SQL 线程追上了中继日志末尾,不代表数据物理一致 - 在原主库执行
FLUSH TABLES WITH READ LOCK;后立即运行SHOW MASTER STATUS;,记下File和Position;然后立刻UNLOCK TABLES;。这个位点才是“冻结快照”的精确坐标,不能用之前随便查的值 - 在新从库(8.0)上执行
SELECT MASTER_POS_WAIT('mysql-bin.000012', 123456789, 30);,等待它真正回放完该位点——这比SHOW SLAVE STATUS更可靠,能捕获隐式卡住的事务
切换那一刻,原主库必须设为只读:SET GLOBAL read_only = ON;,并确认 super_read_only 也已开启(8.0 默认启用),否则应用连接池冷连接仍可能写出脏数据。
切换后第一个要查的命令不是 SHOW SLAVE STATUS
切流完成后,别急着看从库状态,先确认新主库(原 8.0 从库)是否真的接管了写入:
- 在新主库执行
SELECT @@gtid_executed;,对比旧主库停写后的gtid_executed(如果启用了 GTID);若未启用 GTID,则查SHOW MASTER STATUS;并比对Executed_Gtid_Set字段是否覆盖全部 - 在任意从库执行
SELECT * FROM performance_schema.replication_applier_status_by_coordinator\G;,检查APPLYING_TRANSACTION_ORIGINAL_COMMIT_TIMESTAMP是否在持续更新,而不是卡在某个时间戳 - 检查新主库的
slow_query_log和general_log,确认应用写入请求真实到达,而非被中间件路由到旧地址
GTID 模式不是必须,但一旦不用,你就要在每次切换时手算 binlog 位点偏移量——而 5.7 和 8.0 对 ANONYMOUS_GTID_LOG_EVENT 的处理差异,会让这个计算变得极易出错。这点常被忽略,直到从库开始跳过事务或重复执行才暴露。











