必须用utf8mb4而非utf8,因mysql的utf8实为utf8mb3,不支持emoji和部分生僻汉字;仅改character_set_server无效,需同步配置[client]、[mysql]、[mysqld]三段及init_connect,并对已有库表手动alter转换,且应用连接参数也须设为utf8mb4。

必须用 utf8mb4,别碰 utf8 —— 后者在 MySQL 里是 utf8mb3 的别名,不支持 emoji 和部分生僻汉字,生产环境踩坑即线上故障。
为什么不能只改 character_set_server 就完事?
MySQL 字符集生效是分层的:客户端连接、服务端默认、数据库、表、字段,五层各自独立。只改 [mysqld] 段的 character_set_server,只影响“新创建数据库”的默认值,对已有库表、客户端连接、甚至新建表都无直接作用。
-
[client]段漏掉default-character-set=utf8mb4→mysql命令行工具连上去后character_set_client仍是latin1,输中文直接变问号 -
[mysql]段没配 →mysql -e "SELECT '测试'"这类非交互命令可能用错编码,尤其 CI/CD 脚本里容易静默失败 - 没加
init_connect='SET NAMES utf8mb4'→ 应用连接池里某些连接未显式执行SET NAMES,插入时字符集协商失败,报Incorrect string value: '\xF0\x9F\x98\x80'
排序规则选 utf8mb4_unicode_ci 还是 utf8mb4_0900_ai_ci?
MySQL 8.0+ 默认是 utf8mb4_0900_ai_ci(ai = accent insensitive),它比 utf8mb4_unicode_ci 更准,尤其对德语 ä、法语 é 等带重音字符的排序和比较更符合现代 Unicode 标准。但要注意:
- 如果应用已长期运行在
utf8mb4_unicode_ci下,升级排序规则需同步评估 ORDER BY、GROUP BY、索引去重等行为是否变化 -
utf8mb4_bin仅用于明确需要大小写敏感或二进制精确匹配的字段(如 API key、token),不要全库设它,否则WHERE name = 'Alice'会查不到'alice' - 排序规则变更不改变存储,但会影响索引比较逻辑;修改库/表级 collation 后,建议
ANALYZE TABLE更新统计信息
已有生产库怎么安全迁移到 utf8mb4?
不能只靠改配置重启就完事。已有库表的字符集不会自动升级,必须手动转换,且操作有风险:
- 先备份:
mysqldump --databases db_name --set-gtid-purged=OFF --default-character-set=utf8mb4 > backup.sql - 改库:执行
ALTER DATABASE db_name CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci;(仅影响后续新建表) - 改表:对每张含文本字段的表,用
ALTER TABLE tbl_name CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;—— 注意该操作会锁表,大表务必在低峰期做 - 验证:查
SHOW CREATE TABLE tbl_name,确认DEFAULT CHARSET=utf8mb4且字段定义里没残留CHARACTER SET utf8 - 特别注意:若字段类型是
VARCHAR(255)且建在utf8mb3下,转成utf8mb4后实际最大字节数从 765 升到 1020,可能触发max_key_length限制;必要时调小长度或开innodb_large_prefix=ON
最易被忽略的是连接层:即使服务端、库、表全配对了,应用 JDBC URL 里漏了 useUnicode=true&characterEncoding=utf8mb4,或者 Python 的 pymysql.connect(..., charset='utf8mb4') 写成 'utf8',照样乱码。字符集链路只要断一环,数据就不可逆损坏。











