MySQL默认utf8实为utf8mb3,不支持emoji,须全链路统一配置utf8mb4:修改my.cnf、重建表、调整索引长度、应用层显式指定charset。

MySQL 默认的 utf8 实际上是 utf8mb3,最多只支持 3 字节字符,无法存储 emoji(如 ?、?、??),必须显式切换到 utf8mb4 并确保**全链路一致**——否则写入时可能被截断、报错或乱码。
确认当前字符集配置是否真正生效
很多人执行了 SET NAMES utf8mb4 就以为搞定了,但这是会话级临时设置,重启连接就失效;更关键的是,SHOW VARIABLES LIKE 'character%' 显示的只是服务端默认值,不等于实际建表/连接用的字符集。
- 查全局配置:
SHOW VARIABLES LIKE 'character_set_%';和SHOW VARIABLES LIKE 'collation_%';,重点看character_set_server和collation_server - 查具体数据库:
SELECT DEFAULT_CHARACTER_SET_NAME, DEFAULT_COLLATION_NAME FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME = 'your_db'; - 查具体表:
SHOW CREATE TABLE your_table;,确认DEFAULT CHARSET=utf8mb4且COLLATE是utf8mb4_*(推荐utf8mb4_unicode_ci或utf8mb4_0900_ai_ci)
修改 MySQL 配置文件(my.cnf / my.ini)的关键项
仅靠 SQL 命令无法持久化,必须改配置文件并重启 mysqld。注意:不同版本对参数名敏感,5.7+ 推荐统一用 utf8mb4,不要混用 utf8。
- 在
[mysqld]段下添加或修改:character-set-server = utf8mb4collation-server = utf8mb4_unicode_ci - 在
[client]和[mysql]段下添加:default-character-set = utf8mb4(MySQL 8.0+ 已弃用该参数,改用charset = utf8mb4) - 务必删除或注释掉旧的
init_connect='SET NAMES utf8',它会覆盖连接时的字符集
重建现有表和字段以真正支持 emoji
改完配置重启后,新创建的库/表会继承 server 设置,但**已有表不会自动升级**。直接 ALTER TABLE ... CONVERT TO 有风险,尤其含索引或外键时。
- 安全做法:先备份,再执行
ALTER TABLE your_table CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; - 如果字段定义里写了
CHARACTER SET utf8(比如VARCHAR(255) CHARACTER SET utf8),必须显式改成utf8mb4,否则该字段仍走旧编码 - 注意索引长度限制:
utf8mb4下单个字符最多占 4 字节,原来VARCHAR(255)的索引可能超限(InnoDB 索引前缀最大 767 字节 → 实际最多支持 191 个utf8mb4字符),需同步调整:ALTER TABLE your_table MODIFY COLUMN your_col VARCHAR(191) CHARACTER SET utf8mb4;
应用层连接字符串必须显式指定 charset
即使服务端配对了,客户端驱动也可能默认用 latin1 或 utf8 连接。PHP、Python、Java 等都要单独声明,不能依赖 server 默认值。
- PHP PDO:
$pdo = new PDO('mysql:host=localhost;dbname=test;charset=utf8mb4', $user, $pass); - Python PyMySQL:
conn = pymysql.connect(..., charset='utf8mb4') - Java JDBC:
jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8mb4 - Node.js mysql2:
{ charset: 'utf8mb4' }
漏掉这一环,insert emoji 时大概率触发 Incorrect string value 错误,或者存进去变成问号或空格。


















