mysql_upgrade在8.0.16+已弃用、8.0.24+彻底删除,仅用于更新系统库表结构和刷新权限,不处理用户数据、表结构、字符集或sql模式;mysqldump导出后须手动建库并指定兼容字符集再导入。

直接用 mysqldump 导出再在新版本执行 mysql_upgrade 是错的路径——mysql_upgrade 在 MySQL 8.0+ 已被移除,且它从来就不是为“导入数据”设计的工具;它只负责更新系统表结构和权限表,对用户库里的表结构、数据、字符集、SQL 模式完全不处理。
mysqldump 导出后不能靠 mysql_upgrade 恢复数据
mysql_upgrade 在 MySQL 5.7 是个独立命令,但 8.0.16 起已被弃用,8.0.24+ 彻底删除。它的作用仅限于:检查并修复 mysql 系统库中的表(如 user、procs_priv),并刷新权限缓存。它不会读取你导出的 .sql 文件,也不会修改你导入后的业务表。
常见误操作是:
- 导出旧库 → 复制文件到新服务器 → 手动创建库 →
mysql -u root db_name → 再跑 <code>mysql_upgrade - 结果:业务数据看似导入成功,但遇到
ERROR 1067、ERROR 1231或中文乱码时,才发现问题压根没解决
从 5.7 迁移到 8.0 必须显式控制 sql_mode 和默认值
MySQL 8.0 默认启用严格 SQL 模式:STRICT_TRANS_TABLES,NO_ZERO_DATE,NO_ZERO_IN_DATE,而 5.7 导出的建表语句里常含 DEFAULT '0000-00-00' 或 NOT NULL 的 TIMESTAMP 字段,直接导入会报 ERROR 1067 (42000)。
正确做法是导入前临时放宽限制:
- 用
--init-command="SET sql_mode='';"启动会话:mysql -u root -p --init-command="SET sql_mode='';" db_name - 或先连进去手动设:
mysql -u root -p db_name→ 输入SET sql_mode='';→ 再用source /path/to/dump.sql - 更稳妥的方案:导出时就过滤掉非法默认值,加
--skip-create-options,再手工补上兼容定义
导出命令必须带 --compatible=mysql57 和 --default-character-set=utf8mb4
MySQL 8.0 默认排序规则是 utf8mb4_0900_as_cs,5.7 完全不认识,导入时直接报 Unknown character set: 'utf8mb4_0900_as_cs';同时 JSON 字段、隐藏索引等语法也会触发 Syntax error。
导出命令不能只写 mysqldump -u user -p db,必须明确降级兼容:
mysqldump --compatible=mysql57 --default-character-set=utf8mb4 -u user -p db_name > dump.sql- 若含触发器/存储过程/事件,且目标 5.7 不需要,加
--skip-triggers --skip-routines --skip-events - 绝对不要用
--all-databases一键导全库——mysql系统库结构跨版本差异极大,必须单独处理
导入前要手动创建数据库并指定字符集
如果导出文件里含 CREATE DATABASE 语句,而目标 MySQL 8.0 服务端默认字符集是 utf8mb4_0900_as_cs,那新建库会继承该排序规则,后续导入仍可能失败。
推荐流程是:
- 先手动建库:
CREATE DATABASE db_name CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; - 再导入:
mysql -u root -p --default-character-set=utf8mb4 db_name - 检查源库实际字符集:
SHOW CREATE DATABASE db_name;和SHOW CREATE TABLE t1;,别只看my.cnf里的character_set_server
真正容易被忽略的是:TIMESTAMP 字段在 5.7 和 8.0 间的行为断层——explicit_defaults_for_timestamp=OFF 时,8.0 允许全 NULL,5.7 却要求至少一个字段带 CURRENT_TIMESTAMP 默认值;不提前检查并调整,建表就会卡住。











