导出时必须显式指定--default-character-set=utf8mb4,否则mysqldump按server默认字符集(如latin1)输出,导致SET NAMES语句错误引发乱码;导入时也须强制连接编码为utf8mb4,且需验证CHARSET()和COLLATION()结果。

导出时没锁定字符集,dump 文件自带 latin1 头
mysqldump 默认按服务器 character_set_server 编码输出 SQL,宝塔装的 MySQL 往往默认是 latin1 或 utf8(即 utf8mb3),哪怕库和表本身已是 utf8mb4,导出的 SQL 文件开头仍可能是:
SET NAMES latin1;
或
/*!40101 SET NAMES utf8 */;
。这种语句会让导入端按错误编码解析后续中文,直接导致乱码。
实操建议:
- 导出时必须显式指定
--default-character-set=utf8mb4,例如:mysqldump -u root -p --default-character-set=utf8mb4 your_db > backup.sql
- 避免用 phpMyAdmin 图形界面“导出”,它常忽略连接层实际 charset,优先用命令行
- 检查 dump 文件前 20 行,确认有
SET NAMES utf8mb4;
而非其他值
导入时没强制指定连接编码,MySQL 按旧配置执行
即使 dump 文件正确,如果导入时连接未设为 utf8mb4,MySQL 仍会把文件里的中文当 latin1 解析——比如把两个字节的 UTF-8 中文拆成两个乱码字符。
实操建议:
- 不要用
mysql -u root -p your_db 这种裸命令,它不带 charset 声明 - 改用:
mysql -u root -p --default-character-set=utf8mb4 your_db
- 若用 phpMyAdmin 导入,先在首页右上角点「导入」→ 展开「格式特定选项」→ 把「字符集」下拉框手动选为
utf8mb4 - 导入后立刻执行
SELECT CHARSET(), COLLATION();确认当前会话编码
两端 collation 不一致,ORDER BY 或 WHERE LIKE 结果异常
字符集相同但校对规则不同(如一端用 utf8mb4_unicode_ci,另一端用 utf8mb4_general_ci),虽不直接导致存取乱码,但会影响中文排序、大小写匹配、重音符号处理。例如 WHERE name LIKE '%张%' 在 _general_ci 下可能漏匹配带变音的「張」。
实操建议:
- 迁移前后都执行:
SHOW CREATE DATABASE your_db;
和SHOW CREATE TABLE your_table;
,比对COLLATE字段是否完全一致 - 建库时统一用:
CREATE DATABASE `your_db` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
- 已有库可修正:
ALTER DATABASE `your_db` COLLATE = utf8mb4_unicode_ci;
(注意:仅改库 collation 不影响已有表,表需单独改)
PHP 连接层仍走默认编码,查出来还是问号
数据库和 dump 都对了,但 PHP 页面显示仍是问号或方块——大概率是应用连接 MySQL 时没声明 utf8mb4,连接层仍在用 latin1 解析字段值。
实操建议:
- mysqli 方式:连接后**立刻**调用
$mysqli->set_charset("utf8mb4"),不能只靠 DSN 里写charset=utf8 - PDO 方式:DSN 必须含
;charset=utf8mb4,且不能被 PDO::MYSQL_ATTR_INIT_COMMAND 覆盖 - 验证是否生效:在查询前执行
$pdo->query("SELECT CHARSET(), COLLATION()")->fetch(),结果应为utf8mb4和utf8mb4_unicode_ci - 别信
phpinfo()里的default_charset,它只管 HTTP header,跟 MySQL 无关
字符集迁移不是“改完库就完事”的单点操作,导出、导入、连接三者缺一不可;collation 差异虽不引发乱码,但会让中文逻辑行为飘忽不定——这点最容易被跳过验证。











