结论是必须让client、connection、results、database、table五层全对齐为utf8mb4,漏一层就可能丢字节或报incorrect string value错误;mysql的utf8实为utf8mb3,不支持emoji和部分生僻汉字,需确认character_set_client、character_set_connection、character_set_results及show create table结果均为utf8mb4,且连接层必须显式指定utf8mb4而非依赖set names utf8。

直接说结论:不是“改一个地方就行”,而是必须让 client、connection、results、database、table 五层全对齐为 utf8mb4,漏一层就可能丢字节、报 Incorrect string value 错误。
查当前实际用的字符集,别信配置文件或建表语句里的“utf8”
很多人执行了 SHOW VARIABLES LIKE 'character%',看到 character_set_server = utf8 就以为万事大吉——但 MySQL 的 utf8 实际是 utf8mb3,不支持 emoji 和部分生僻汉字(比如「?」「?」)。真正要确认的是这三项是否都等于 utf8mb4:
character_set_clientcharacter_set_connectioncharacter_set_results
再单独查表:SHOW CREATE TABLE your_table_name,看建表语句里有没有 CHARACTER SET utf8mb4。如果只写了 CHARACTER SET utf8 或压根没写,默认会继承库级设置,而老库很可能还是 latin1 或 utf8。
连接层必须显式指定 utf8mb4,不能靠 SET NAMES utf8 补救
SET NAMES utf8 是个常见陷阱:它等价于同时设 character_set_client、character_set_connection、character_set_results 为 utf8(即 utf8mb3),对 4 字节字符完全无效。正确做法是:
- 命令行连接加参数:
mysql -u root -p --default-character-set=utf8mb4 - JDBC URL 必须带:
?useUnicode=true&characterEncoding=utf8mb4 - Spring Boot 配置里
spring.datasource.url后面也要加这个参数 - PHP 的
mysqli_set_charset($conn, 'utf8mb4')或 PDO DSN 中加;charset=utf8mb4
注意:SET NAMES utf8mb4 只对当前连接生效,连接池重连后失效,所以必须在连接建立时就定死,不能运行时补。
改已有表不能只靠 ALTER DATABASE,必须逐表执行 CONVERT TO CHARACTER SET
ALTER DATABASE your_db CHARACTER SET utf8mb4 只影响后续新建的表,对已有表字段毫无作用。真正生效的操作是:
- 改整个表(含所有文本字段):
ALTER TABLE your_table CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci - 只改某列(比如字段类型是
TEXT):ALTER TABLE your_table MODIFY column_name TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci - 改完立刻验证:
SHOW CREATE TABLE your_table,确认字段定义里出现了CHARACTER SET utf8mb4
特别注意:如果字段类型是 ENUM 或 SET,CONVERT TO 会失败,得用 MODIFY 单独处理;另外 utf8mb4_unicode_ci 在 MySQL 8.0+ 推荐换成 utf8mb4_0900_as_cs,大小写和重音更准确。
服务端配置要改 my.cnf 里的 character-set-server,不是 default-character-set
MySQL 5.5.3+ 已废弃 default-character-set,写它会被忽略。正确写法是:
[mysqld] character-set-server = utf8mb4 collation-server = utf8mb4_unicode_ci [client] default-character-set = utf8mb4
改完必须重启 MySQL 服务,否则 character_set_server 不会变。验证方式仍是 SHOW VARIABLES LIKE 'character_set_server',必须返回 utf8mb4,而不是 utf8。
最常被忽略的一点:即使服务端、数据库、表全设成 utf8mb4,只要应用连接时没传 characterEncoding=utf8mb4,数据在进入 MySQL 前就被截断了——你查表里永远看不到乱码,但 INSERT 会报错或静默丢字节。











