MySQL导入含Emoji的SQL文件报错“Incorrect string value”的根本原因是默认字符集utf8mb3不支持4字节UTF-8字符(如?、??),须全程统一使用utf8mb4:包括文件编码、连接字符集、表/列字符集及服务端默认字符集;mysqldump导出需加--default-character-set=utf8mb4,导入前确认SQL文件为UTF-8编码,导入命令须显式指定--default-character-set=utf8mb4。
MySQL 导入含 Emoji 的 SQL 文件报错:Incorrect string value
根本原因是 mysql 默认字符集不支持 4 字节 utf-8 字符(emoji 大多属于此范围),哪怕客户端声称用了 utf8,实际用的仍是 utf8(即 utf8mb3),它最多只支持 3 字节字符,遇到 ?、?? 这类就会炸。
必须让整个链路都用 utf8mb4:文件编码、连接字符集、表/列字符集、服务端默认字符集——缺一不可。
-
mysqldump导出时加--default-character-set=utf8mb4,否则导出的 SQL 文件头部可能没声明编码,或写成utf8 - 导入前确认 SQL 文件本身是 UTF-8 编码(不是 ANSI 或 GBK),可用
file -i your.sql或 VS Code 右下角查看;若为其他编码,先用iconv -f gbk -t utf-8 input.sql > output.sql转换 - 导入命令必须显式指定字符集:
mysql --default-character-set=utf8mb4 -u root -p database_name ,漏掉这个参数,即使数据库设了 <code>utf8mb4,连接层仍可能回落到latin1或utf8
检查并修正 MySQL 服务端字符集配置
光改命令行没用,如果 MySQL 服务端没配好,新创建的表、字段默认还是 utf8,后续插入 Emoji 依然失败。
关键看三个层级是否统一为 utf8mb4:
- 全局变量:
character_set_server和collation_server应为utf8mb4和utf8mb4_unicode_ci(查法:SHOW VARIABLES LIKE 'character_set_server';) - 数据库级:
CREATE DATABASE db_name CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci;,已有库用ALTER DATABASE db_name CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci; - 表/列级:即使库设对了,旧表可能仍是
utf8,需逐个修正:ALTER TABLE tbl_name CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
注意:utf8mb4_unicode_ci 比 utf8mb4_general_ci 更准(后者已弃用),排序和比较行为更符合现代 Unicode 规范。
连接层与客户端字符集必须同步设置
很多报错其实发生在应用连接 MySQL 时没传对字符集,比如 Python 的 pymysql 或 Node.js 的 mysql2 默认不发 SET NAMES utf8mb4。
- PHP PDO:DSN 中加
;charset=utf8mb4,例如mysql:host=localhost;dbname=test;charset=utf8mb4 - Python pymysql:初始化连接时传
charset='utf8mb4'参数,不能只靠init_command="SET NAMES utf8mb4" - Java JDBC URL:加上
?characterEncoding=utf8mb4&serverTimezone=UTC,且驱动版本建议 ≥ 8.0.13(老版本对utf8mb4支持不稳) - 命令行客户端:除了导入时加
--default-character-set=utf8mb4,日常登录也建议加,或在~/.my.cnf里写死:[client]\ndefault-character-set = utf8mb4
验证 Emoji 是否真能存进去,别信“看起来成功了”
常见假成功:SQL 文件导入没报错,但 Emoji 被静默替换成 ? 或空格,查 SELECT 看不到异常,其实是乱码存进去了。
- 手动插一条测试:
INSERT INTO test_table (content) VALUES ('Hello ? 世界 ?');,再SELECT HEX(content)查看——正确存储时,? 对应F09F9197(4 字节),若看到3F(问号)或截断的C3B1,说明某一层仍是utf8mb3 - 检查字段定义:
SHOW CREATE TABLE test_table;,确认列字符集是utf8mb4,不是utf8;同时留意ROW_FORMAT=DYNAMIC或COMPRESSED(InnoDB 表),否则utf8mb4+ 长文本可能触发Row size too large - 如果用 phpMyAdmin 导入,它有自己的字符集处理逻辑,优先用命令行导入,避免中间转码
最常被跳过的环节是:以为改了 my.cnf 就万事大吉,忘了重启 mysqld,或者没检查当前会话的 character_set_client、character_set_results——它们可能还是 latin1。










