MySQL 5.7+ 和 8.0 中 my.cnf 必须在 [client]、[mysql]、[mysqld] 三段显式配置 utf8mb4:[client] 加 default-character-set=utf8mb4 影响所有客户端工具;[mysql] 加 default-character-set=utf8mb4 专用于命令行客户端;[mysqld] 加 character-set-server=utf8mb4 和 collation-server=utf8mb4_0900_ai_ci(8.0)或 utf8mb4_unicode_ci(5.7),缺一则 emoji 存储或显示异常。

MySQL 的 utf8mb4 不是改一个配置就自动全链路生效的——服务端、连接层、数据库/表/字段三级结构、应用客户端,四者必须全部对齐,缺一环 emoji 就存不进去或显示为问号。
my.cnf 里哪三段必须写 utf8mb4
MySQL 5.7+ 和 8.0 都要求 [client]、[mysql]、[mysqld] 三段同时显式配置,否则会“局部生效、全局失效”:
-
[client]加default-character-set = utf8mb4:影响所有客户端工具(Navicat、DBeaver、python-mysql 连接等)默认用什么字符集发起连接 -
[mysql]加default-character-set = utf8mb4:专用于mysql命令行客户端自身(和[client]有重叠,但不写可能被忽略) -
[mysqld]加character-set-server = utf8mb4和collation-server = utf8mb4_0900_ai_ci(MySQL 8.0 推荐)或utf8mb4_unicode_ci(5.7 兼容):决定新库/新表的默认值,也影响 SQL 文本解析
漏掉 collation-server 是最常见错误:即使 character_set_server 是 utf8mb4,新建库仍继承 latin1_swedish_ci,后续建表不显式指定就会延续错误排序规则。
连接后怎么验证字符集真生效了
登录 MySQL 后不能只看 character_set_server,必须查这 6 项:
character_set_clientcharacter_set_connectioncharacter_set_databasecharacter_set_resultscharacter_set_servercollation_server
执行 SHOW VARIABLES LIKE 'character\_set%'; 和 SHOW VARIABLES LIKE 'collation%';,6 项中前 5 项必须是 utf8mb4,最后一项必须是 utf8mb4_0900_ai_ci 或 utf8mb4_unicode_ci。若其中任一项是 utf8 或 latin1,说明某一层配置没覆盖到。
特别注意:Linux/macOS 下用 mysql -u root -p 默认走 socket 连接,此时 [client] 段可能未被读取——尤其当 my.cnf 放在非标准路径时。可强制走 TCP 测试:mysql -h 127.0.0.1 -u root -p,再查 STATUS; 看 “Current client” 是否显示 via TCP/IP。
已有数据库和表怎么安全升级到 utf8mb4
改完配置重启 mysqld 只影响新创建的对象,老库老表不会自动升级。升级需分步操作,且容易踩坑:
- 先改库:
ALTER DATABASE db_name CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci;(仅影响后续新建表) - 再改表:
ALTER TABLE t CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;—— 但可能报Specified key was too long - 报错原因:InnoDB 默认索引长度上限 767 字节,
VARCHAR(255)在 utf8mb4 下最多占 1020 字节;临时解法是缩成VARCHAR(191)(191×4=764),根治法是启用innodb_large_prefix=ON、innodb_file_format=Barracuda、innodb_file_per_table=ON,并加ROW_FORMAT=DYNAMIC -
TEXT类型字段不会随CONVERT自动升级,必须显式执行:ALTER TABLE t MODIFY c TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
应用连接字符串里不加 charset=utf8mb4,前面全白干
即使服务端、表结构全设对了,只要客户端连接没声明字符集,MySQL 就按默认(常为 latin1)解析字节流,emoji 进来就是乱码或直接被截断:
- JDBC:
jdbc:mysql://host:3306/db?useUnicode=true&characterEncoding=utf8mb4(Connector/J ≥ 5.1.13) - PHP PDO:
mysql:host=localhost;dbname=test;charset=utf8mb4 - Node.js mysql2:
{ charset: 'utf8mb4' } - Django:
OPTIONS={'charset': 'utf8mb4'}必须显式写,ORM 不继承数据库全局设置
最容易被忽略的是:MySQL 8.0 默认排序规则是 utf8mb4_0900_ai_ci,而很多老项目依赖 utf8mb4_unicode_ci 的行为(比如德语 ß 和 ss 的等价判断)。混用会导致 ERROR 1267: Illegal mix of collations,迁移时得逐字段核对是否需要保留旧排序规则。


















