必须先查清源库字符集再迁移,执行show variables like 'character_set%'及查询information_schema确认真实编码,避免因默认值差异或latin1存中文导致乱码。

查清当前库表字符集再动手
迁移前不确认源库字符集,90% 的乱码问题都出在这一步。别信“默认是 utf8mb4”这种说法,MySQL 5.7 和 8.0 默认值不同,而且很多老库是 latin1 或 utf8(即 utf8mb3)。
执行这条命令看真实情况:
SHOW VARIABLES LIKE 'character_set%';
重点盯住 character_set_server、collation_server,再对每个库、每张表单独查:
SELECT DEFAULT_CHARACTER_SET_NAME, DEFAULT_COLLATION_NAME FROM information_schema.SCHEMATA WHERE SCHEMA_NAME = 'your_db';
SELECT CCSA.character_set_name FROM information_schema.`TABLES` T, information_schema.`COLLATION_CHARACTER_SET_APPLICABILITY` CCSA WHERE CCSA.collation_name = T.table_collation AND T.table_schema = "your_db" AND T.table_name = "your_table";
- 如果返回
utf8,注意它不是真正的 UTF-8,最多存 3 字节,emoji 和部分生僻字会截断 -
latin1存中文本身就是错的,只是靠客户端“硬解”蒙混过关,一换环境就崩 - 哪怕显示是
utf8mb4,也要确认collation是utf8mb4_0900_as_cs(8.0)或utf8mb4_unicode_ci(5.7),否则排序和比较行为可能异常
mysqldump 导出时必须显式指定字符集
不加参数直接 mysqldump,它会按客户端连接的字符集导出,而这个连接很可能被 my.cnf 或环境变量悄悄覆盖,导致 dump 文件里混着不同编码的 SQL。
安全做法是两条腿走路:服务端指定 + 客户端强制:
mysqldump --default-character-set=utf8mb4 -h host -u user -p your_db > dump.sql
- 必须带
--default-character-set=utf8mb4,不能只靠-c或--set-charset - 如果源库真是
latin1编码存的中文,先用--default-character-set=latin1导出,再用 iconv 转成 utf8mb4,硬切会双编码 - dump 文件开头应看到
SET NAMES utf8mb4;,没这句基本等于白干
导入时字符集不匹配会导致“二次乱码”
很多人导出对了,但导入时忘了环境一致性。最典型的是:用 mysql 命令行导入,但终端 locale 是 en_US.UTF-8,而 MySQL server 的 character_set_client 却是 latin1 —— 这时候 SQL 里的中文会被 server 当作 latin1 解码,再存成 utf8mb4,结果变成“汉字→乱码→再转义→更乱”。
导入命令必须锁定三件事:
mysql --default-character-set=utf8mb4 -h host -u user -p your_db < dump.sql
- 命令行参数
--default-character-set=utf8mb4比SET NAMES更底层,能影响连接初始化阶段 - 检查导入后
SELECT HEX(col) FROM table LIMIT 1;:正常中文是E4B8ADE69687这种 4 字节十六进制,如果看到C3A4C2B8C2ADC3A6C296C287就是 double-encoded - 如果已发生 double-encoded,别删库重来,可用
CONVERT(CAST(CONVERT(col USING latin1) AS BINARY) USING utf8mb4)临时修复单列
ALTER TABLE 改字符集不是万能解药
看到表是 utf8 就想 ALTER TABLE ... CONVERT TO CHARACTER SET utf8mb4?小心踩坑。
这条语句实际做三件事:改表默认字符集、改所有文本列类型、逐行 convert 数据。但它不会动已存在的索引长度限制,也不会自动调大 VARCHAR 定义 —— 而 utf8mb4 下同样文字占更多字节,容易触发 Specified key was too long 错误。
- 执行前先看索引长度:
SHOW CREATE TABLE your_table;,如果VARCHAR(255)加了索引,utf8mb4 下最大索引长度超限(InnoDB 默认 767 字节),得先ALTER TABLE ... MODIFY col VARCHAR(191) -
CONVERT TO会锁全表,大表慎用;只改默认字符集用ALTER TABLE ... CHARACTER SET = utf8mb4,不碰数据 - TEXT 类型字段在
CONVERT TO后可能隐式变成MEDIUMTEXT,应用层如果做了类型强校验,可能报错
字符集迁移不是开关一拨就完事,每个环节的编码视角都要对齐:存储、传输、解析、显示。少一个 utf8mb4,就多一分乱码风险。










