必须同时配置[client]、[mysql]、[mysqld]三段:[client]和[mysql]设default-character-set=utf8mb4,[mysqld]设character-set-server=utf8mb4及collation-server=utf8mb4_unicode_ci,缺一则连接链路不全,必现乱码。

乱码不是数据丢了,是编码链路中某一段把中文当成了别的字符在解——character_set_client、character_set_connection、character_set_results 这三项只要有一个不是 utf8mb4,就必现乱码。
怎么快速确认当前连接是否真用 utf8mb4?
别看配置文件,先查实时会话:
执行 SHOW VARIABLES LIKE 'character\_set%';,重点盯住这三行:
-
character_set_client:客户端发来的字节按什么编码解析 -
character_set_connection:SQL 解析和转换时用的中间编码 -
character_set_results:返回给客户端的结果用什么编码打包
只要其中任意一个是 latin1、utf8(即 utf8mb3)或 gbk,插入中文就会被截断、替换或报 Incorrect string value 错误。即使表定义是 utf8mb4,这三层不对齐也白搭。
为什么不能只改表或库的字符集?
ALTER DATABASE 或 ALTER TABLE 只影响存储层,不改变连接行为。常见误区:
-
ALTER DATABASE db_name CHARACTER SET utf8mb4;—— 仅让新表默认用 utf8mb4,已有表字段不变 -
ALTER TABLE t CONVERT TO CHARACTER SET utf8mb4;—— 会重建表,但若索引字段是VARCHAR(255),可能因长度超限(InnoDB 单索引 767 字节限制)直接失败 - 没同步改
collation,比如仍用utf8mb4_general_ci,排序和比较行为可能不符合预期
真正要改的是整条链:客户端发、服务端收、服务端存、服务端返——四段缺一不可。
命令行和应用连接必须显式指定 utf8mb4
SET NAMES utf8mb4 只对当前连接生效,程序重启或连接池重连后失效,不能靠它“补救”:
- 命令行启动加参数:
mysql --default-character-set=utf8mb4 -u root -p - JDBC URL 必须带:
?useUnicode=true&characterEncoding=utf8mb4 - Spring Boot 配置里
spring.datasource.url后面也要拼上相同参数 - my.cnf 必须同时配三段:
[client](影响所有客户端工具)、[mysql](专管 mysql 命令行)、[mysqld](服务端),只写[mysqld]是无效的
改完配置必须 systemctl restart mysqld,reload 不生效。
utf8mb4 不是可选升级,是硬性底线
MySQL 的 utf8 实际是 utf8mb3,最多支持 3 字节字符,无法存 emoji(如 \xF0\x9F\x98\x80)或部分生僻汉字(如 “?”)。一旦业务涉及用户昵称、评论、微信/钉钉对接,utf8mb4 就不是“建议”,而是存储前提。
容易被忽略的一点:存储过程体内的中文字符串(比如 SELECT '你好' 或注释)是在客户端发送 SQL 时就被解析的。如果建过程前没 SET NAMES utf8mb4,那两个汉字会被按错误编码存进 mysql.proc 表,后续改字符集也救不回来。











