MySQL 5.7 升级到 8.0 后的字符集问题,90% 是 utf8mb4_general_ci 和 utf8mb4_0900_ai_ci 混用导致的隐式转换失败,根本原因是字段、连接、数据库三者 collation 不对齐,需通过 SHOW FULL COLUMNS 和 SELECT @@collation_connection 等命令查清真实值,并用 ALTER TABLE MODIFY 统一字段 collation 才能治本。

直接说结论:MySQL 5.7 升级到 8.0 后的字符集问题,90% 是 utf8mb4_general_ci 和 utf8mb4_0900_ai_ci 混用导致的隐式转换失败,不是配置写错,而是字段、连接、数据库三者 collation 不对齐。
查清字段真实 collation,别信 SHOW CREATE TABLE 的注释
SHOW CREATE TABLE 输出里带 COLLATE utf8mb4_0900_ai_ci 注释,不代表字段真用了它——实际生效的只看字段定义里白纸黑字写的部分。旧表从 5.7 迁入,哪怕导出时加了新 collation 注释,只要建表语句没显式声明,字段就还是 utf8mb4_general_ci。
- 用
SHOW FULL COLUMNS FROM table_name LIKE 'col_name';查字段真实Collation值 - 用
SELECT @@collation_connection, @@collation_database;看当前会话和库默认值 - 特别注意
FIND_IN_SET()、JSON_VALUE()、UNION这类操作,它们不走collation_server,只认字段和参数各自的 collation
ALTER TABLE MODIFY 是唯一治本动作
临时在 SQL 里加 COLLATE utf8mb4_0900_ai_ci 能绕过单条报错,但无法修复数据层不一致;改 collation_server 或 init_connect 对已有字段完全无效。
- 执行
ALTER TABLE t MODIFY col VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci; - TEXT 类型字段也要单独处理:
MODIFY col TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci; - 若字段是索引前缀(如
VARCHAR(500)只索引前 191 字符),注意utf8mb4_0900_ai_ci的索引长度计算更严格,可能需调小前缀长度 - 批量改表建议先锁表:
SET innodb_fast_shutdown = 0;,再逐个执行
mysql 系统库 collation 必须统一为 utf8mb4_0900_ai_ci
升级失败常卡在启动阶段,报 Illegal mix of collations 或直接 abort,大概率是 mysql 库本身还用着 utf8mb4_general_ci。8.0 要求整个数据字典统一使用 utf8mb4_0900_ai_ci,否则连系统表都加载不了。
- 检查:
SELECT SCHEMA_NAME, DEFAULT_COLLATION_NAME FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME = 'mysql'; - 修复:
ALTER DATABASE mysql COLLATE = utf8mb4_0900_ai_ci; - 注意:不能只改库默认值,还要确保
mysql.user、mysql.db等关键表的字段 collation 也同步更新,否则权限校验会崩 - 改完立即跑
mysqlcheck --repair --use-frm mysql,防止 frm 与 ibd 不一致
JOIN 和子查询场景最容易漏检
单表查询看着正常,一 JOIN 就变慢或报错,说明关联字段 collation 不一致。哪怕两个字段都是 utf8mb4,只要一个是 _general_ci、一个是 _0900_ai_ci,MySQL 就会在 join buffer 中做全量转换,索引失效、性能断崖式下跌。
- 用
EXPLAIN SELECT ... JOIN ...看type是否退化为ALL,key是否为NULL - 查两边字段的 collation:
SHOW FULL COLUMNS FROM t1 LIKE 'join_col';和SHOW FULL COLUMNS FROM t2 LIKE 'join_col'; - 修复必须双向对齐:要么改左边字段,要么改右边字段,不能只修一边
- 应用层 JDBC 连接串要加
useUnicode=true&characterEncoding=utf8mb4&serverTimezone=UTC,否则驱动送参时可能用错编码
最麻烦的不是改 collation,而是改完后发现某些业务 SQL 依赖旧排序规则的细微行为(比如大小写敏感度、重音符号比较逻辑),这些没法靠脚本扫出来,得靠真实流量压测验证。


















