mysql 5.7 升级至 8.0 需结构检查、运行时适配与客户端协同,不可仅靠替换函数名或变量值;必须停写后执行 mysqlcheck --check-upgrade 和 util.checkforserverupgrade() 扫描不兼容项并逐条修复。

不能靠“替换函数名”或“改变量值”实现平滑升级——MySQL 5.7 到 8.0 的系统函数与变量变更属于语义级不兼容,必须通过结构检查、运行时适配和客户端协同来应对。
mysqlcheck --check-upgrade 必须在停写后执行
这个命令是唯一能提前暴露系统表结构不兼容的工具,比如 ENUM 默认值为空、TEXT 字段写了 DEFAULT ''、列名用了 rank(8.0 保留字)等。它不是校验数据损坏,而是检查是否满足 8.0 元数据要求:
- 必须在业务停写后运行:
mysqlcheck -u root -p --all-databases --check-upgrade - 报
The table does not comply with the current version of MySQL就得立刻修复,常见动作是ALTER TABLE tbl MODIFY col TEXT去掉默认值,或用反引号包裹列名:`rank` - 对含
JSON字段的表,mysqlcheck不报错也不代表安全,建议补查:SELECT * FROM tbl WHERE json_valid(col) = 0
util.checkForServerUpgrade() 报 ERROR 必须清零
这是 Oracle 官方唯一推荐的跨版本兼容性扫描器,比 mysqlcheck 更深,专扫语义变更。它识别不到的问题,mysqld 启动时会直接拒载:
- 必须用匹配目标版本的
mysqlsh(如升 8.0.27 就用 8.0.27 的 shell),混用 5.7 的 shell 会漏检 - 执行命令:
./mysqlsh -uroot -p -S /tmp/mysql.sock -e "util.checkForServerUpgrade({'configPath': '/etc/my.cnf'})" - ERROR 级别条目必须逐条处理,例如:
Usage of utf8mb3 charset→ 改表字符集;Column name 'rank' is a reserved keyword→ 重命名或加反引号 - WARNING 也不能跳过,例如:
caching_sha2_password plugin not supported by client→ 升级 JDBC 驱动或改认证插件
sql_mode 和系统变量不能“降级”,只能适配
MySQL 8.0 移除了 NO_AUTO_CREATE_USER,默认启用 STRICT_TRANS_TABLES,且 sql_mode 默认值已变。所谓“降级变量”是伪命题,实际要做的只有两件事:
- 导出前确认业务 SQL 是否依赖宽松模式,尤其是
INSERT INTO t VALUES ()这类空值插入,需提前补全字段或改写逻辑 - 启动 8.0 后不要试图把
sql_mode改回 5.7 的旧值,而应在应用层显式声明所需模式,例如连接串加sql_mode=STRICT_TRANS_TABLES,NO_ZERO_DATE - 废弃变量如
query_cache_type、explicit_defaults_for_timestamp必须从my.cnf中彻底删除或注释,否则 8.0 启动直接报unknown variable并静默失败
系统函数行为变化必须靠客户端代码兜底
像 UNIX_TIMESTAMP()、JSON_EXTRACT()、GROUP BY 语义等,在 8.0 中有实质性变更。没有“降级函数”的配置项,只能由上层控制:
-
UNIX_TIMESTAMP(NOW())在 5.7 返回 int,在 8.0 可能带小数秒 → 应用层统一用FLOOR(UNIX_TIMESTAMP(NOW())) -
JSON_EXTRACT(json_col, '$.key')8.0 返回带引号字符串,5.7 不带 → ORM 层加 trim 或改用JSON_UNQUOTE(JSON_EXTRACT(...)) -
GROUP BY严格模式开启后,SELECT a, b FROM t GROUP BY a会报错 → 所有模糊分组 SQL 必须显式列出所有非聚合字段,或加ANY_VALUE(b)
真正容易被忽略的是:这些函数和变量的变更,往往在导入数据后不报错,而是在某次特定查询、某个时间点、某类客户端连接时才触发。上线前必须用真实业务流量回放验证,而不是只跑一遍 DDL 检查。











