mysql 8.0默认字符集虽为utf8mb4,但实际生效需同时配置mysqld[mysql]三段并重启验证,仅改character-set-server无效;必须设utf8mb4及对应校对规则,并显式转换旧库表、客户端连接也需指定charset。

MySQL 8.0默认字符集已经是utf8mb4,但服务端配置仍可能不生效
MySQL 8.0 默认的 character_set_server 和 collation_server 确实是 utf8mb4 和 utf8mb4_0900_ai_ci,但很多线上实例是从 5.7 升级而来,或使用了自定义配置文件(如 /etc/my.cnf),导致实际启动时仍加载旧值。执行 SHOW VARIABLES LIKE 'character\_set\_server'; 是唯一可靠验证方式,不能只看文档或版本号。
- 检查当前值:
SELECT @@character_set_server, @@collation_server; - 若返回
latin1或utf8(注意:不是utf8mb4),说明配置未生效或被覆盖 -
utf8在 MySQL 中是阉割版,最多存 3 字节字符(不支持 emoji、部分生僻汉字),必须避免
修改my.cnf时必须同时设置[client]、[mysql]和[mysqld]三处
只改 [mysqld] 段会导致客户端连接仍用默认字符集,建表/插入时隐式降级。常见现象是:表结构显示 utf8mb4,但插入 emoji 后变成问号或截断。
-
[client]:控制 mysql 命令行客户端默认连接字符集(影响mysql -u...) -
[mysql]:专用于 mysql CLI 工具自身的初始化设置(常被忽略) -
[mysqld]:服务端默认值,影响新数据库、新表、连接的默认 collation
最小必要配置如下:
[client] default-character-set = utf8mb4 [mysql] default-character-set = utf8mb4 [mysqld] character-set-server = utf8mb4 collation-server = utf8mb4_0900_ai_ci skip-character-set-client-handshake = OFF
skip-character-set-client-handshake = OFF 是关键:它允许客户端声明自己的字符集(比如 JDBC 的 useUnicode=true&characterEncoding=utf8mb4),而不是强制服务端覆盖。设为 ON 会直接忽略客户端请求,极易出错。
utf8mb4_0900_ai_ci vs utf8mb4_unicode_ci:排序行为差异真实存在
MySQL 8.0 默认用 utf8mb4_0900_ai_ci,它基于 Unicode 9.0.0,对大小写、重音完全不敏感(ai = accent insensitive,ci = case insensitive)。而老项目常用 utf8mb4_unicode_ci(基于 Unicode 4.0.0),两者在中文拼音排序、德语 ß/SS 处理、土耳其语 I/i 规则上表现不同。
- 升级后
ORDER BY name结果变乱?很可能是排序规则变更导致 - 应用依赖
COLLATE utf8mb4_unicode_ci显式指定?需同步检查 SQL 中硬编码的 collation - 如需兼容旧行为,可全局设
collation-server = utf8mb4_unicode_ci,但无法回退到 MySQL 5.7 的utf8mb4_general_ci(已废弃)
已有库/表/列不会自动升级,必须显式ALTER
修改配置并重启 MySQL 只影响新建对象。已有数据库、表、列的字符集仍是旧值,SHOW CREATE TABLE 里还能看到 DEFAULT CHARSET=latin1 或 utf8。
- 改库:
ALTER DATABASE db_name CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci; - 改表:
ALTER TABLE tbl_name CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;(推荐,连字段一起转) - 只改列(谨慎):
ALTER TABLE tbl_name MODIFY col_name VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci; - 执行前务必备份;
CONVERT TO会锁表,大表考虑在低峰期操作
最易被忽略的是客户端连接参数——即使服务端全配对,JDBC URL 缺少 characterEncoding=utf8mb4、Python 的 pymysql.connect(..., charset='utf8mb4') 没写,照样存不进 emoji。











