改 collation_server 不能解决报错,它只影响新连接默认排序规则,对已有字段、join、find_in_set 等无效;需先查清表和字段真实 collation,再用 alter table 修改字段 collation 治本。

改 collation_server 不能解决报错,它只影响新连接的默认排序规则,对已有字段、JOIN、FIND_IN_SET 等场景完全无效。
查清表和字段的真实 collation 是第一步
错误不是凭空出现的,而是因为 5.7 创建的表用的是 utf8mb4_general_ci,8.0 新建表默认用 utf8mb4_0900_ai_ci,两者在比较时无法自动转换。你得先摸清现状:
- 执行
SHOW FULL COLUMNS FROM your_table;,看每列的Collation值 - 执行
SHOW CREATE TABLE your_table;,确认表级COLLATE和字段定义是否显式声明 - 特别注意
FIND_IN_SET()、UNION、JOIN ON这类隐式比较操作——它们会把两边字段的 collation 拿出来直接比,不走collation_server
ALTER TABLE 修改字段 collation 是治本动作
临时加 COLLATE utf8mb4_0900_ai_ci 到 SQL 里能绕过单条报错,但不解决数据层不一致。批量修复必须落到字段定义上:
- 用
ALTER TABLE t MODIFY col VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;替换旧 collation - 如果字段是索引前缀(比如
VARCHAR(500)但只索引前 191 字符),要检查长度是否超限:utf8mb4_0900_ai_ci的索引长度计算更严格,可能需调小前缀长度 - 别漏掉
TEXT类型字段,它们也能带 collation,且同样参与比较
FIND_IN_SET 和 JSON_VALUE 报错必须显式统一 collation
FIND_IN_SET() 返回值默认继承第一个参数的 collation,而第二个参数(逗号分隔字符串)若来自不同 collation 的字段或变量,就会触发 Illegal mix of collations;JSON_VALUE() 在 8.0 中也要求显式声明返回类型与 collation:
- 写成
FIND_IN_SET(col1 COLLATE utf8mb4_0900_ai_ci, @var COLLATE utf8mb4_0900_ai_ci) - 虚拟列 + 索引写法已失效,必须改用
CREATE INDEX idx ON t (JSON_VALUE(data, '$.field' RETURNING CHAR(100) COLLATE utf8mb4_0900_ai_ci)) - 别依赖函数自动推导 collation,MySQL 8.0 对隐式转换更保守,宁可报错也不静默降级
最容易被跳过的其实是 SHOW CREATE TABLE 输出里的 collation 注释——它可能带 utf8mb4_0900_ai_ci,但字段定义里没写,导入到 5.7 就炸;反过来,8.0 导出时若没清理旧注释,也会让迁移脚本误判。真实 collation 只认字段定义和表定义里白纸黑字写的那部分,其余全是干扰项。











