在线升级仅支持同一大版本内小版本平滑迭代(如8.0.33→8.0.34),跨大版本(如5.7→8.0)或含MyISAM表必须离线升级;离线升级需停服、替换二进制、重初始化数据目录、迁移并清理配置;主从与组复制需按兼容顺序滚动升级,并严格校验插件、参数及GTID一致性。

在线升级只适用于小版本平滑迭代
MySQL 官方只保证同一大版本内的小版本在线升级可行,比如 8.0.33 → 8.0.34;跨大版本(如 5.7 → 8.0)或含 MyISAM 表的实例,mysqld --upgrade 会直接失败,甚至损坏元数据。这是因为 8.0 彻底重构了数据字典,mysql 系统库中 user、db 等表已移除,全部由内部 dictionary 管理,5.7 的系统表空间无法识别。
- 必须使用相同构建方式:都是官方二进制包,或都是源码编译,混用会导致 ABI 不兼容
- 启用插件(如
audit_log、keyring)前需确认新版是否支持对应 ABI 版本,否则启动即报错 - 在线升级后仍需手动验证:字符集默认值变化(
utf8mb4_0900_as_cs)、JSON 索引行为、慢日志字段新增、sql_mode默认收紧等
离线升级是跨版本和生产环境的唯一稳妥路径
所谓“离线”,本质是停服 + 替换二进制 + 重初始化数据目录 + 迁移配置,不是简单覆盖安装。很多人跳过关键检查点,结果 service mysql start 启动失败,排查半天才发现是配置项残留或初始化未完成。
- 备份前务必运行:
mysqlcheck --all-databases --check-upgrade,它会明确指出哪些表需ALTER TABLE ... UPGRADE PARTITIONING - 替换
mysqld二进制后,先别急着启动服务,用测试命令验证初始化:mysqld --initialize-insecure --datadir=/var/lib/mysql --basedir=/usr/local/mysql-8.0 -
my.cnf中必须清理废弃参数,例如query_cache_type、explicit_defaults_for_timestamp,否则 8.0 启动直接报unknown variable
主从集群下如何最小化升级窗口
高可用环境不能全量停机,得靠角色切换实现“伪在线”:先升级从库 → 提升为新主 → 再升级原主。但 GTID 和复制过滤器的兼容性稍有不慎就会中断复制。
- 若原主启用了
gtid_mode=ON,升级后必须保持enforce_gtid_consistency=ON,否则从库 IO 线程拉取 binlog 时拒绝连接 -
replicate-ignore-db在 8.0 已被移除,必须改写为replication-filter语法,并重启 mysqld 才生效 - 升级从库前,在主库执行
STOP SLAVE IO_THREAD,等Seconds_Behind_Master = 0再停服务,避免 relay log 断层导致数据不一致
组复制(Group Replication)必须滚动升级
组内成员不能同时升级,必须逐个进行,否则新旧版本间特性不兼容——比如旧节点不支持 8.0 新增的 binlog_transaction_compression,或新节点依赖已弃用的 group_replication_recovery_complete_at 参数,都会导致组通信异常甚至分裂。
- 滚动升级期间,组中可存在混合版本(如
8.0.17和8.0.34),但要严格按 MySQL 文档规定的兼容顺序操作 - 升级前查当前组状态:
SELECT MEMBER_HOST, MEMBER_PORT, MEMBER_VERSION FROM performance_schema.replication_group_members; - 升级过程中禁止执行 DDL 或大事务,避免因版本差异导致 group commit 失败或 XA 锁等待超时
最容易被忽略的是插件兼容性和配置清理——哪怕只多留了一行 skip-external-locking,8.0 启动就卡住;哪怕 audit_log 插件没更新,mysqld 就静默退出。升级不是替换二进制那么简单,而是对整个运行时契约的重新校准。










