小版本升级(如5.7.30→5.7.40)优先选就地升级,只需停服、替换二进制文件、启动并运行mysql_upgrade;需提前执行mysqlcheck --check-upgrade检查兼容性,升级后验证error.log无“failed to upgrade table”报错,并强制--force重跑mysql_upgrade以防遗漏。

小版本升级(如 5.7.30 → 5.7.40)优先选就地升级
只要操作系统、glibc 版本、文件系统没变,且确认没用到已弃用的插件或存储引擎(比如 MyISAM 的 mysql.plugin 表),就地升级是最快最稳妥的选择。MySQL 官方对小版本的就地升级支持成熟,启动后自动执行 mysql_upgrade 即可完成系统库更新。
常见错误现象包括:mysql_upgrade 报错 “Table 'mysql.plugin' doesn't exist”,这往往是因为旧版中该表被误删或损坏;或者启动时提示 Unknown system variable 'validate_password_length',说明配置文件里残留了 5.7 早期版本才有的变量名。
实操建议:
- 停服务前先执行
mysqlcheck --all-databases --check-upgrade,提前发现不兼容表 - 升级后必须检查
error.log中是否出现Failed to upgrade table mysql.xxx类报错 - 不要跳过
mysql_upgrade步骤,即使提示“already upgraded”,也要加--force强制重跑一次
跨大版本(如 5.7 → 8.0)必须用逻辑迁移
就地升级在 5.7 到 8.0 场景下不是“不推荐”,而是“大概率失败”。MySQL 8.0 启动时会做数据字典强校验,而 5.7 中大量“能跑”的状态会被直接拒绝:比如 sql_mode 里含 NO_AUTO_CREATE_USER,会卡在启动阶段报错 Variable 'sql_mode' can't be set to the value of 'NO_AUTO_CREATE_USER';又比如 utf8mb3 字符集建的表带四字节 emoji,元数据校验直接失败。
逻辑迁移本质是“隔离语义差异”,把问题暴露在导入前或导入时报错,而不是凌晨三点数据库起不来。
实操建议:
- 导出必须加
--single-transaction和--set-gtid-purged=OFF(若未启用 GTID),否则可能锁全库或导入后复制中断 - 导入前在 8.0 实例手动执行
SET GLOBAL sql_mode = 'STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION',避免大批语法报错 - 导入后立刻验证:
SELECT DEFAULT_COLLATION_NAME FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME = 'your_db'确认是否为utf8mb4_0900_ai_ci;SHOW CREATE TABLE your_table检查字符集是否已升为utf8mb4
认证插件和用户权限是逻辑迁移中最容易漏掉的一环
MySQL 8.0 默认使用 caching_sha2_password 插件,但老应用连接驱动(尤其 Java 8u221 之前、PHP 7.3 之前)根本不识别,一连就报 Client does not support authentication protocol。这不是网络或密码问题,是协议不兼容。
很多人导完数据、调通 SQL,上线后才发现所有应用连不上——因为忘了重建用户。
实操建议:
- 导出时用
mysqldump --no-create-info --skip-triggers --compact -u root -p mysql user单独导出用户表结构和数据 - 导入后,对每个业务用户显式指定旧插件:
CREATE USER 'app_user'@'%' IDENTIFIED WITH mysql_native_password BY 'pwd'; - 如果必须用新插件,需同步升级客户端驱动,并在连接串中加
&serverTimezone=UTC&allowPublicKeyRetrieval=true(Java)或对应参数
主从架构下,复制过渡法比纯逻辑迁移更可控
逻辑迁移要停写、导出、导入、切流,对大库来说窗口太长。而复制过渡法(即用 MySQL 8.0 新建从库,挂到 5.7 主库上)能实现近乎零停机:等复制追平、验证无误后,只切一次流量,原主库可留作回滚备用。
但要注意:MySQL 5.7 → 8.0 的复制不是默认开启的,必须满足两个前提——主库开启 binlog_format = ROW,且从库启用 slave_type_conversions = ALL_NON_LOSSY,否则遇到字段类型隐式转换(如 TINYINT → ENUM)会直接中断复制。
实操建议:
- 搭建 8.0 从库前,先在测试环境用
mysqlsh运行util.checkForServerUpgrade(),它会扫描全库并输出具体哪张表、哪个字段、哪条 SQL 有风险 - 复制建立后,持续观察
SHOW SLAVE STATUS\G中的Seconds_Behind_Master和SQL_Delay,避免延迟累积导致切换时数据丢失 - 切换前务必在从库执行
STOP SLAVE; SET GLOBAL read_only = OFF;,否则应用写入会报错
sql_mode 兼容性、没检查用户认证插件、也没跑 mysqlsh 的兼容性扫描——这些动作不耗时,却决定成败。











