MySQL零停机升级依赖主从切换而非原地升级,需确保版本间复制兼容(如5.7→8.0可行,反向不可),配合AdminAPI可自动化滚动升级,但须严控配置、时区、大小写策略及认证插件等隐性差异。

MySQL 主从切换实现零停机升级
MySQL 本身不支持原地热升级(比如从 5.7 直接升到 8.0),所谓“无停机时间升级”,本质是靠架构切换而非单实例就地升级。最成熟、可控的方式是构建主从复制拓扑,将新版本实例作为从库拉取旧版本主库的 binlog,待数据追平后执行角色切换。
关键前提是:新旧版本间必须满足 replication compatibility。例如:
- 5.7 → 8.0 支持(但需关闭
sql_mode中的NO_AUTO_CREATE_USER等已移除项) - 8.0 → 5.7 不支持(高版本 binlog event 类型低版本无法解析)
- 跨大版本时,
mysql_upgrade不可用于在线实例,只能在从库停写后执行(且仅限同版本升级场景)
使用 MySQL Shell 的 AdminAPI 自动化滚动升级
MySQL 8.0.19+ 内置的 AdminAPI(通过 mysqlsh)可管理 InnoDB Cluster,支持对集群节点逐个升级而不中断服务。它底层仍是主从切换逻辑,但封装了状态检查、故障隔离、自动重试等细节。
实操要点:
- 确保所有节点启用
group_replication且运行在兼容模式(如group_replication_consistency=AFTER) - 升级前用
cluster.checkInstanceConfiguration()验证目标实例配置(尤其binlog_format=ROW、enforce_gtid_consistency=ON) - 执行
cluster.upgradeMetadata()仅更新元数据版本,不触碰数据;真正的二进制升级需先停掉该节点的mysqld,替换二进制,再以--upgrade=MINIMAL启动
pt-online-schema-change 不能用于版本升级
有人误以为 pt-online-schema-change 或 gh-ost 能做版本升级——它们只解决「表结构变更时避免锁表」的问题,和 MySQL 服务进程的二进制替换、系统表迁移、字符集默认行为变更等完全无关。
典型误用后果:
- 在 5.7 主库上用
gh-ost迁移一张表,再把该表所在的实例升级到 8.0 →mysql.user表结构已变,权限系统直接失效 - 跳过
mysql_upgrade步骤直接启动 8.0 二进制读取 5.7 数据目录 → 启动失败并报错Table 'mysql.role_edges' doesn't exist - 未重放完所有 binlog 就切换流量 → 出现主键冲突或丢失事务
升级后必须验证的三个隐性断裂点
即使切换成功,以下三点极易被忽略,导致后续业务异常:
-
TIMEZONE行为差异:5.7 默认用系统时区,8.0 默认用SYSTEM但首次启动会尝试写入mysql.time_zone表;若未加载时区表,NOW()和CONVERT_TZ()结果错乱 -
lower_case_table_names默认值变化:Linux 下 5.7 默认为 0,8.0 默认为 1 —— 若应用硬编码了大小写混用的表名,查询会突然返回空结果 -
default_authentication_plugin:8.0 默认改用caching_sha2_password,老客户端(如 MySQL 5.6 JDBC driver)连接会报错Unknown authentication plugin caching_sha2_password
这些不是“升级没完成”,而是“升级完成了但环境没对齐”。上线前必须用真实业务 SQL 在新实例上回放验证,不能只看 SHOW SLAVE STATUS\G 的 Seconds_Behind_Master: 0。










