直接改collation_server无效,必须先查清表和字段真实collation;5.7与8.0默认collation不同(utf8mb4_general_ci vs utf8mb4_0900_ai_ci),JOIN、FIND_IN_SET等操作会因collation不一致触发1267报错;治本需ALTER TABLE修改字段collation,临时加COLLATE仅绕过单条错误。

直接改 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 对隐式转换更保守,宁可报错也不静默降级
跨版本导入时遇到 “Unknown collation” 错误怎么救
从 5.7 或更早导出的 SQL,在 MySQL 8.0 导入常卡在:Unknown collation: 'utf8mb4_unicode_520_ci' 或 COLLATION 'utf8_general_ci' is not valid for CHARACTER SET 'utf8mb4'。这是 dump 文件里硬编码了旧规则,必须文本替换:
- 用
grep -n "utf8mb4_0900_ai_ci" your_dump.sql定位全部出现位置,别依赖编辑器“全文件替换”功能,有些可能藏在注释或长字符串里 - 优先处理
CREATE TABLE语句末尾的COLLATE=utf8mb4_0900_ai_ci,再查每个VARCHAR列定义后的COLLATE子句 - 如果导出时用了
--skip-set-charset,则SET NAMES语句里也可能含该排序规则,需一并替换
最容易被跳过的其实是 SHOW CREATE TABLE 输出里的 collation 注释——它可能带 utf8mb4_0900_ai_ci,但字段定义里没写,导入到 5.7 就炸;反过来,8.0 导出时若没清理旧注释,也会让迁移脚本误判。真实 collation 只认字段定义和表定义里白纸黑字写的那部分,其余全是干扰项。


















