必须文本替换dump文件中的旧排序规则:将utf8mb4_unicode_520_ci改为utf8mb4_0900_ai_ci,删改CHARSET=utf8mb4 COLLATE=utf8_general_ci等非法组合,并统一库表字段collation为utf8mb4_0900_ai_ci。
这是从 MySQL 5.7 或更早版本导出的 SQL 文件,在 8.0 中导入时报的典型错误,比如 Unknown collation: 'utf8mb4_unicode_520_ci' 或 COLLATION 'utf8_general_ci' is not valid for CHARACTER SET 'utf8mb4'。根本原因是 dump 文件里硬编码了 8.0 不认识的旧排序规则,或者把已废弃的 utf8 字符集写进了建表语句。
sed 批量替换:把所有 utf8mb4_unicode_520_ci 换成 utf8mb4_0900_ai_ci
CHARSET=utf8mb4 COLLATE=utf8_general_ci 的行——utf8_general_ci 在 utf8mb4 字符集下根本不合法,必须改为 utf8mb4_0900_ai_ci 或 utf8mb4_unicode_ci
CREATE DATABASE ... DEFAULT CHARSET=utf8,要改成 DEFAULT CHARSET=utf8mb4,否则 8.0 会拒绝解析导入成功但一查就崩,说明字段级 collation 混用了。MySQL 8.0 对 JOIN、FIND_IN_SET()、子查询等操作强制校验两边 collation 是否一致,不匹配就直接报错,不会静默转换。
SELECT TABLE_NAME, COLUMN_NAME, COLLATION_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = 'your_db' AND COLLATION_NAME NOT IN ('utf8mb4_0900_ai_ci');,找出所有非 8.0 默认的列FIND_IN_SET() 的两个参数:第一个是字段(可能带旧 collation),第二个是变量或字符串字面量(默认继承 session 的 collation,通常是 utf8mb4_0900_ai_ci)——两边不一致就会触发错误JSON_VALUE() 也一样,必须显式声明返回类型和 collation,比如 JSON_VALUE(data, '$.field' RETURNING CHAR(100) COLLATE utf8mb4_0900_ai_ci)
CONVERT TO 改的是整张表的默认 collation,但不会覆盖已有字段上显式声明的旧 collation;MODIFY 是精准修正单个字段,必须带完整类型定义。
ALTER TABLE t CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;,它会让新字段继承这个 collation,但对已有字段中显式写了 COLLATE utf8mb4_general_ci 的列无效ALTER TABLE t MODIFY col VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
SET SESSION innodb_lock_wait_timeout = 300;,避免 phpMyAdmin 或宝塔面板超时中断同一字符串在 utf8mb4_general_ci 和 utf8mb4_0900_ai_ci 下可能被判定为“相等”或“不等”,导致唯一约束行为突变。这不是数据错了,是 collation 切换后比较逻辑变了。
SELECT * FROM t WHERE col = '张三' COLLATE utf8mb4_unicode_ci; 和 COLLATE utf8mb4_0900_ai_ci 结果是否一致utf8mb4_bin 建的 UNIQUE 索引,目标库却按 utf8mb4_0900_ai_ci 解析,小写/大写可能被当成不同值,插入时就会撞车ALTER TABLE t DROP INDEX idx_name; ALTER TABLE t ADD UNIQUE INDEX idx_name (col);
真正麻烦的不是改 collation 这一步,而是你得确认业务 SQL 里所有隐式比较点——比如 ORDER BY、GROUP BY、视图定义、存储过程里的临时表——它们全依赖 collation 行为。一个没扫到,上线就出数据逻辑偏差。