mysql升级过程中的数据备份与恢复策略

4次阅读

升级mysql必须做逻辑备份,禁用物理拷贝;恢复时跳过mysql系统库并初始化;GTID模式需校验gtid_purged;8.0已废弃mysql_upgrade,改由mysqld自动升级;注意默认排序规则变更。

mysql升级过程中的数据备份与恢复策略

升级前必须做完整逻辑备份,而非仅依赖物理拷贝

MySQL 升级(尤其是跨大版本,如 5.7 → 8.0)时,mysqldumpmydumper 生成的逻辑备份是唯一可验证、可移植、兼容性可控的备份方式。直接拷贝 datadir 在多数情况下不可靠:InnoDB 表空间格式可能变更(如 8.0 默认启用 innodb_file_per_table=ON 且引入数据字典表),且 MySQL 8.0 的 mysql 系统库结构与 5.7 不兼容,强行复用会导致启动失败或权限异常。

实操建议:

  • 使用 mysqldump --all-databases --single-transaction --routines --Events --triggers --set-gtid-purged=OFF(若未启用 GTID)或 --set-gtid-purged=ON(若已启用 GTID)导出全量数据
  • 避免使用 --skip-lock-tables,它在多事务场景下可能破坏一致性
  • 对大库(>100 GB),优先选用 mydumper 并配合 myloader,支持并行导出/导入,且默认按表粒度加锁,影响更小
  • 务必校验导出文件末尾是否含 EOF 或成功退出码($? 为 0),常见错误如磁盘满、连接中断会导致 dump 截断但无明显报错

升级后恢复时需跳过系统库,手动初始化 mysql 数据库

MySQL 8.0 将原 mysql 库中的权限表(userdb 等)替换为数据字典表(存于 mysql.ibdibdata1 中),且结构完全不向下兼容。若在 8.0 实例中直接导入 5.7 的 mysqldump 全库备份,会因 mysql 库冲突导致恢复失败,甚至损坏新实例的数据字典。

正确做法是分两步:

  • 先用 mysqld --initialize --user=mysql 初始化 8.0 实例,生成全新的 mysql 系统库和 root 密码(记录在 Error log 中)
  • 再用 mysql -u root -p 恢复,但必须提前从 backup.sql 中剔除 CREATE DATABASE `mysql` 及其所有 INSERT INTO `mysql`.* 语句;可用 sed '/^CREATE DATABASE `mysql`/,/^/*/d' backup.sql > app_backup.sql 快速过滤(注意匹配实际注释结尾)
  • 若备份中含自定义函数/存储过程,需确认其语法兼容性(如 8.0 移除了 DEFINER 的部分宽松校验,可能报 ERROR 1449 (HY000): The user specified as a definer ('xxx'@'%') does not exist),应提前用 SHOW CREATE function 检查并重写 DEFINER

GTID 模式下升级必须保持 gtid_mode=ON + enforce_gtid_consistency=ON 且校验 gtid_purged

若原实例启用了 GTID(gtid_mode=ON),升级后若未正确继承 gtid_purged 值,会导致主从复制断裂或新实例拒绝执行任何事务。MySQL 8.0 要求 gtid_modeenforce_gtid_consistency 必须同时为 ON 才允许启动,而 5.7 的 dump 默认不包含 SET @@GLOBAL.GTID_PURGED 语句(除非显式加 --set-gtid-purged=ON)。

关键检查点:

  • 导出前确认源库 select @@GLOBAL.gtid_purged; 返回非空值;若为空,需先执行 FLUSH LOGSRESET MASTER(仅限测试环境,生产慎用)
  • dump 文件开头应含类似 SET @@GLOBAL.GTID_PURGED='aaa-bbb-ccc:1-100'; 的语句;若缺失,需手动追加(值来自上一步查询结果)
  • 恢复后立即执行 SELECT @@GLOBAL.gtid_executed, @@GLOBAL.gtid_purged;,确保二者一致且覆盖 dump 中声明的范围,否则后续开启复制会报 Could not execute Write_rows event on table

升级后必须运行 mysql_upgrade 吗?8.0 已废弃该工具

MySQL 5.7 及更早版本要求升级后运行 mysql_upgrade 来更新系统表结构、修复权限视图。但该工具在 MySQL 8.0 中已被彻底移除——所有系统库升级操作由 mysqld 启动时自动完成。若在 8.0 中误执行 mysql_upgrade,会提示 Unknown suffix '.' encountered 或直接报错退出。

替代方案只有两个:

  • 确保以 mysqld --upgrade=FORCE 启动(仅首次启动必需,后续无需重复);该参数会触发内部数据字典升级流程
  • 观察 error log,确认出现类似 Server upgraded from version '50732' to '80033'Created new data dictionary with version ... 的日志条目,即表示升级成功
  • 切勿手动修改 mysql 库下的任何表(如 innodb_index_stats),8.0 的统计信息已转为数据字典内建表,直接 DML 会引发崩溃

最易被忽略的是字符集与排序规则的隐式变更:MySQL 8.0 默认 collation_server=utf8mb4_0900_ai_ci,而 5.7 是 utf8mb4_general_ci。即使备份恢复成功,应用若未显式指定 COLLATE,ORDER BY、GROUP BY 结果可能不同,且 utf8mb4_0900_ai_ci 对某些 emoji 的排序行为也与旧版不一致。

text=ZqhQzanResources