mysql 8.0升级需重点处理五类兼容性问题:禁用no_auto_create_user导致grant建用户失败;默认字符集utf8mb4引发索引长度超限;only_full_group_by开启使非分组字段查询报错;系统表结构变更致备份还原失败;直连mysql库的运维脚本失效。

MySQL 8.0 默认禁用 sql_mode=NO_AUTO_CREATE_USER 导致权限语句失败
MySQL 5.6 允许在 GRANT 语句中隐式创建用户,比如直接执行 GRANT SELECT ON db.* TO 'u'@'%' IDENTIFIED BY 'p';;但 8.0 默认移除了 NO_AUTO_CREATE_USER,这条语句会报错 ERROR 1410 (42000): You are not allowed to create a user with GRANT。
必须显式拆成两步:
- 先用
CREATE USER 'u'@'%' IDENTIFIED BY 'p'; - 再用
GRANT SELECT ON db.* TO 'u'@'%';
如果迁移脚本里大量混用旧写法,光靠 mysqldump --compatible=mysql40 搞不定——这个参数不处理权限语句。建议提前 grep 扫描所有 GRANT ... IDENTIFIED BY 模式。
默认字符集从 latin1 变成 utf8mb4,建表语句行为不一致
5.6 中 CREATE TABLE t (s VARCHAR(10)); 实际用的是 latin1,而 8.0 默认用 utf8mb4。这不只是存储变宽的问题,更关键的是:索引长度限制变了——VARCHAR(255) 在 latin1 下索引能建,在 utf8mb4 下可能超限(因为单字符最多占 4 字节),报错 ERROR 1071 (42000): Specified key was too long。
迁移前要检查所有带索引的字符串字段:
- 用
SHOW CREATE TABLE看实际字符集和排序规则 - 对
VARCHAR字段,若定义长度接近 191(255×3÷4≈191),且有索引,大概率要缩到VARCHAR(191)或改用前缀索引 - 不要依赖配置文件里的
collation-server,8.0 中init_connect不影响 CREATE 语句的默认字符集
ONLY_FULL_GROUP_BY 默认开启,SELECT 里混用非分组字段直接报错
这是最常踩的坑:5.6 默认关着,很多老业务 SQL 写成 SELECT id, name, COUNT(*) FROM t GROUP BY id;(name 没在 GROUP BY 里也没用聚合函数),5.6 能跑,8.0 直接报错 ERROR 1055 (42000): Expression #2 of SELECT list is not in GROUP BY clause。
不能简单关掉 sql_mode —— 关了只是掩盖问题,可能返回不可靠结果。正确做法是:
- 逐条查出报错 SQL,用
EXPLAIN FORMAT=TREE看执行逻辑是否真需要那个非分组字段 - 如果确实需要,补上
ANY_VALUE(name)或改写为子查询/窗口函数(8.0 支持) - 别全局设
sql_mode='',至少保留STRICT_TRANS_TABLES和NO_ZERO_DATE
系统表结构变更导致备份还原失败或权限异常
8.0 把权限相关数据全挪到 mysql.user 表的列里(比如 authentication_string 替代 Password),还加了 password_history、password_reuse_interval 等字段。直接用 5.6 的 mysqldump --all-databases 还原到 8.0,会因表结构不匹配失败。
安全迁移路径只有一条:
- 用 5.6 的
mysqldump --no-create-info --skip-triggers --compact导出数据(跳过系统库) - 用 8.0 的
mysql_upgrade初始化新实例后再导入 - 千万别用
cp data/或xtrabackup跨大版本拷贝数据目录——8.0 的ibdata1格式和 redo log 结构都变了
真正麻烦的是那些绕过 MySQL 权限系统、直连 mysql 库做用户管理的运维脚本——它们八成会在 8.0 里读不到字段或写错列。











