根本原因是备份时未指定--default-character-set导致字符集错配,mysqldump按character_set_client读表但忽略实际表字符集,造成双重编码;还原时客户端默认latin1解析UTF-8字节流,进一步加剧乱码。

mysqldump 备份时漏了 --default-character-set 就已经埋雷了
乱码不是恢复阶段才发生的,而是备份那一刻就错了。mysqldump 默认用 character_set_client 的值去读表数据——这个 session 变量常是 utf8mb4,但你的表实际是 latin1,它就会把字节当 utf8 解一遍再写进 SQL 文件,造成“双重编码”。
查真实字符集别信 SHOW VARIABLES LIKE 'character_set%' 里的 client 值,得看表本身:SHOW CREATE TABLE table_name,盯住 DEFAULT CHARSET=xxx 字段。
不确定时,每个表都手动查一遍;别假设全库统一。
还原命令不带 --default-character-set 等于默认用 latin1 解 UTF-8 字节
MySQL 客户端解析 SQL 文件时,不加参数就按编译默认值(通常是 latin1)解码,哪怕你库是 utf8mb4,汉字也会被截断或错映射。
正确写法:mysql --default-character-set=utf8mb4 -u root -p db_name < backup.sql
错误写法:mysql -u root -p db_name < backup.sql(缺参数)
Windows 下别用 cmd 执行,它的代码页常是 GBK,会二次污染;改用 Git Bash 或 PowerShell。
如果报 Unknown character set: 'utf8mb4',说明客户端太老,升级或临时换 utf8(不推荐,emoji 会丢)。
SQL 文件开头没 SET NAMES,光靠命令行参数可能不够
有些旧 dump 脚本只生成建表语句,没初始化连接编码。这时即使加了 --default-character-set,字段级字符集仍可能被忽略。
打开 backup.sql,在第一行插入:SET NAMES utf8mb4;
确保这行在任何 CREATE DATABASE 或 USE 之前。
如果文件里已有 SET NAMES latin1,必须替换成 utf8mb4,否则它会覆盖命令行参数。
别指望 JDBC 风格的 charset=utf8mb4 URL 参数——mysql 命令行根本不认这个。
还原后 SELECT 还是乱码?重点检查三处实际存储层
命令跑成功不代表完事。MySQL 有四层编码:客户端、连接、数据库、表/列。其中任意一层不匹配,SELECT 出来就是乱的。
运行:SELECT @@character_set_client, @@character_set_connection, @@character_set_results; —— 三个值必须都是 utf8mb4。
再查表结构:SHOW CREATE TABLE t1;,确认 ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 和字段定义里有没有 CHARACTER SET utf8mb4。ALTER TABLE ... CONVERT TO CHARACTER SET utf8mb4 不会修复已错数据,它只改元数据和后续写入行为;已存的乱码字节不会被重解——比如 \xE6\x88\x91 在 latin1 下是三个独立字符,在 utf8mb4 下才是“我”,但 CONVERT TO 不做这种逆向映射。
SHOW CREATE TABLE 都得亲手看一遍,不能跳。



















