mysql服务端必须显式设置utf8mb4,仅靠客户端声明无效;需在my.cnf的[mysqld]段配置character-set-server=utf8mb4和collation-server=utf8mb4_unicode_ci,重启后验证@@character_set_server为utf8mb4,否则表/列级设置仅为补丁。

MySQL服务端必须显式设置utf8mb4,不能只靠客户端声明
很多用户以为在连接时指定charset=utf8mb4就万事大吉,结果插入Emoji仍报错Incorrect string value。根本原因是MySQL服务端默认字符集没改,SHOW VARIABLES LIKE 'character_set%'会发现character_set_server仍是latin1或utf8(注意:MySQL的utf8实际是utf8mb3,不支持4字节Unicode)。
必须修改my.cnf(Linux)或my.ini(Windows)配置文件,在[mysqld]段落中加入:
[mysqld] character-set-server = utf8mb4 collation-server = utf8mb4_unicode_ci
重启MySQL后验证:SELECT @@character_set_server, @@collation_server;应返回utf8mb4和utf8mb4_unicode_ci。跳过这步,后续所有表/列级设置都只是“打补丁”,不治本。
建表与修改表时,CHARACTER SET和COLLATE必须同时指定
即使服务端已设为utf8mb4,新建表若不显式声明,仍可能继承旧默认值。尤其对已有表执行ALTER TABLE时,仅改列字符集不够,索引字段长度也可能超限。
- 新建表:在
CREATE TABLE末尾加DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci - 修改现有表:先改表默认字符集,再改具体列(特别是
VARCHAR类字段) - 关键点:含Emoji的
VARCHAR(255)字段,若用utf8mb4且ROW_FORMAT=COMPACT,InnoDB单行最大长度可能被突破——需确认innodb_large_prefix=ON且innodb_file_format=Barracuda
安全写法示例:
ALTER TABLE users CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; -- 若提示 "Specified key was too long",则先调整字段长度或启用大前缀支持
连接层必须同步使用utf8mb4,且驱动版本要够新
客户端连接不匹配会导致“服务端支持但存不进”——典型现象是插入无报错,但查出来变成???或空格。常见原因:
- PHP PDO未在DSN中加
;charset=utf8mb4,或mysql_set_charset()已废弃,必须用set_charset('utf8mb4') - Python
pymysql需显式传charset='utf8mb4'参数;旧版MySQLdb根本不支持utf8mb4 - Java JDBC URL要带
useUnicode=true&characterEncoding=utf8mb4,且驱动版本≥5.1.13(低版本会静默降级为utf8)
验证连接是否生效:SHOW VARIABLES LIKE 'character_set_client';和SHOW VARIABLES LIKE 'character_set_connection';都应为utf8mb4。
utf8mb4_unicode_ci和utf8mb4_0900_as_cs选哪个?
排序规则影响大小写敏感性和Unicode比较逻辑。MySQL 8.0+默认用utf8mb4_0900_as_cs(重音敏感、大小写敏感),而老项目常用utf8mb4_unicode_ci(重音不敏感、大小写不敏感)。
选择依据:
- 若业务需要精确区分
é和e、A和a,选_as_cs;否则_unicode_ci更兼容历史行为 - 切勿混用:同一库中不同表用不同collation,JOIN或ORDER BY可能出意料结果
- 升级时注意:
utf8mb4_unicode_ci在MySQL 8.0中已被标记为deprecated,未来会被移除
生产环境切换前,务必在测试库用真实数据跑一遍SELECT ... ORDER BY和WHERE name LIKE '%...%',确认排序和匹配逻辑不变。
最常被忽略的是innodb_large_prefix和ROW_FORMAT组合问题——哪怕所有字符集都设对了,只要索引字段太长又没开大前缀支持,ALTER TABLE就会失败,而错误信息完全不提字符集的事。











