必须经5.6→5.7→8.0两步升级:因mysql 8.0彻底重构为innodb托管的事务性数据字典,跳过5.7会导致字典初始化失败、系统表损坏及mysqld启动失败。

直接升风险极高,必须逐步升级:5.6 → 5.7 → 8.0。MySQL 官方不支持跨大版本就地升级,5.6 到 8.0 中间缺失的元数据结构、系统表格式、认证机制变更会导致数据字典损坏或启动失败。
为什么不能跳过 5.7 直接升到 8.0
MySQL 8.0 的数据字典(mysql 库)是全 InnoDB 存储、事务化、不可直接写入的,而 5.6 的 mysql 表仍是 MyISAM。中间必须经由 5.7 过渡——5.7 已开始将部分系统表转为 InnoDB,并引入兼容层,为 8.0 的原子化字典做铺垫。跳过 5.7 会导致 mysqld 启动时校验失败,报错类似:Failed to open the data dictionary table mysql.user 或 Unknown table engine 'InnoDB'(实际是引擎识别逻辑错乱)。
5.6 → 5.7 升级的关键动作
这是整个路径中最容易被低估的一环,但恰恰决定后续成败:
- 必须先将 5.6 升到 5.7 最新 GA 版本(如
5.7.33),而非任意 5.7.x;旧版 5.7(如 5.7.9)对 8.0 的兼容性支持不完整 - 执行
mysql_upgrade前,确保innodb_fast_shutdown=0,否则缓冲区未刷盘,5.7 启动时可能因页损坏拒绝加载表空间 -
mysql_upgrade不是“万能修复工具”:它只更新系统表结构,不会自动转换 MyISAM 用户表。必须手动运行ALTER TABLE t ENGINE=InnoDB批量迁移 - 检查并清理已废弃的 SQL mode,例如移除
NO_AUTO_CREATE_USER,否则 5.7 启动会警告,8.0 直接拒绝启动
5.7 → 8.0 升级时最常踩的坑
很多人以为过了 5.7 就安全了,结果卡在 8.0 启动环节:
-
default_authentication_plugin必须显式设为mysql_native_password,否则应用连接报Client does not support authentication protocol requested by server - 8.0 默认启用严格 SQL mode(如
STRICT_TRANS_TABLES),老应用里带隐式类型转换或 GROUP BY 不完备的 SQL 会直接报错,不能只靠sql_mode回退,得同步改代码 - 字符集别硬切:5.6 多数库是
latin1或utf8(3 字节),8.0 默认utf8mb4。必须在 5.7 阶段就完成ALTER DATABASE ... CONVERT TO CHARACTER SET utf8mb4,否则 8.0 导入时可能截断或报错 -
mysql_upgrade在 8.0 中已被移除,升级后不能运行它——新版本通过--upgrade=FORCE参数在首次启动时自动触发字典升级,误执行会提示Command not found
逻辑备份还原比就地升级更可控
即使走完 5.6→5.7→8.0 路径,生产环境仍建议用 mysqldump 或 mydumper 做逻辑迁移,而不是复用旧 datadir:
- 就地升级一旦失败,回滚需依赖完整物理备份 + binlog,恢复窗口长且易出错
- 逻辑导出会强制暴露兼容性问题:比如 5.6 允许的
CREATE TABLE t(c TINYINT) DEFAULT '',在 8.0 dump 中会被拒绝导入 - 导出时加
--single-transaction --routines --triggers --events,避免锁表和遗漏对象;导入前在 8.0 实例中先CREATE DATABASE并指定CHARACTER SET utf8mb4 - 大库(>100GB)慎用
mysqldump,优先选xtrabackup做物理备份,再在新机器上还原 +--copy-back,最后启动时加--upgrade=FORCE
实际操作中,最难的不是命令怎么敲,而是确认每一处 SQL 行为变化是否被业务感知——比如 5.6 中 SELECT * FROM t GROUP BY a 能跑,8.0 会报错,这种问题往往要等上线后第一笔报表查询才暴露。所以测试必须覆盖真实查询流量,不能只跑单元测试。











