必须先升从库再升主库,因新版本从库兼容旧主库binlog,而旧从库无法解析新主库日志;gtid环境下顺序更严格,需确保server_uuid不变、gtid_executed正常,升级后须验证延迟为0及gtid集合一致。

先升从库,再升主库,不能反过来
主从复制环境里升级 MySQL,顺序错了就可能中断复制、丢数据、甚至主从错乱。核心原则是:所有从库必须先完成升级并稳定运行,主库最后升。这是因为新版本从库通常能兼容旧版本主库的 binlog 格式和协议(向下兼容),但旧版本从库无法解析新版本主库生成的某些日志内容(比如 MySQL 8.0+ 的 DDL 事件格式变更、密码认证插件升级后的握手逻辑)。
常见错误现象:ERROR 1236 (HY000) 报“binlog event with unknown type”或“Could not parse relay log event entry”,基本就是主库已升、从库没跟上导致的。
- 升级前确认所有从库
Seconds_Behind_Master = 0,且Slave_IO_Running和Slave_SQL_Running均为Yes - 逐台升级从库:停
STOP SLAVE→ 替换二进制 → 启动 mysqld → 执行START SLAVE→ 观察SHOW SLAVE STATUS\G是否恢复正常 - 每台从库升级后至少观察 15 分钟,确认无
Retrieved_Gtid_Set与Executed_Gtid_Set差异扩大、无重试连接或 SQL 线程卡住
GTID 开启时,升级顺序更严格
如果复制启用了 GTID(gtid_mode = ON),顺序不仅影响连通性,还直接影响事务一致性。MySQL 8.0+ 对 GTID 的校验更严格,旧版本从库在收到新主库的 GTID 事务后,可能因 server_uuid 解析逻辑变化或 gtid_executed 表结构差异而拒绝应用。
关键点:所有从库必须在主库升级前完成 GTID 兼容性准备,包括:
- 确保每台从库的
server_uuid在升级前后保持不变(不要重建数据目录或重装) - 升级前检查
SELECT @@GLOBAL.gtid_executed;是否可正常返回;若报错或为空,说明 GTID 状态异常,需先修复 - 避免在升级过程中执行
RESET MASTER或RESET SLAVE ALL—— 这会清空 GTID 集合,导致后续同步失败
滚动升级期间禁止写入主库?不,但要控流量
主库升级前最后一刻仍可写,但必须控制写入节奏。真实场景中,没人真等业务零写入才升级——那不现实。关键是把风险收口到可控范围内。
实操建议:
- 升级窗口前 5 分钟,通知应用层暂停非关键写(如日志表、统计表插入),只保留核心交易链路
- 主库升级前执行
FLUSH TABLES WITH READ LOCK;(注意:仅适用于低并发场景;高并发建议用SET GLOBAL read_only = ON+ 应用层写开关配合) - 升级完成后,立刻执行
UNLOCK TABLES;或SET GLOBAL read_only = OFF;,再验证主从同步状态 - 切记:
FLUSH TABLES WITH READ LOCK会阻塞所有 DML,包括复制线程的 SQL 执行,所以它只能在从库全部升级完毕、主库即将升级的最后阶段使用
升级后必须验证复制延迟与 GTID 连续性
服务起来不代表复制就稳了。很多团队跳过这步,结果上线几小时后才发现某张表数据静默丢失,或者某笔事务在从库被跳过。
重点验证项:
- 检查所有从库的
Seconds_Behind_Master是否持续为 0,且Retrieved_Gtid_Set和Executed_Gtid_Set完全相等 - 在主库执行一条带明显标识的 INSERT,例如:
INSERT INTO test_sync VALUES (NOW(), 'upgrade-check');,然后立刻在所有从库查是否同步到位 - 运行
mysqlbinlog --base64-output=DECODE-ROWS -v mysql-bin.0000xx | grep -A5 -B5 "upgrade-check",确认该事务在 binlog 中完整存在且未被截断
最易被忽略的是 GTID 集合的隐式分裂——比如某从库因网络抖动短暂断连,重连后虽自动补日志,但 Executed_Gtid_Set 可能漏掉中间一段。这种问题不会报错,但会导致后续故障转移时选错主库。











