mysql 8.0 默认用 utf8mb4 是为解决旧 utf8(即 utf8mb3)和 latin1 无法存储 emoji、生僻汉字、越南语多音符字等 4 字节字符的问题,插入会报 incorrect string value 错误;utf8mb4 才是完整 utf-8 实现,自 5.5.3 引入,8.0 仅设为默认以补全基础能力。

MySQL 8.0 默认用 utf8mb4,不是为了“更现代”,而是 latin1 和旧 utf8(即 utf8mb3)根本存不了 emoji、生僻汉字、某些越南语字符——插入直接报 Incorrect string value 错误。
为什么旧 utf8 在 MySQL 里不能存 emoji
MySQL 的 utf8 是个历史包袱:它只支持最多 3 字节的 Unicode 编码(utf8mb3),而 emoji(如 ?)、U+10000 以上的生僻汉字(如 ?)、带多重变音符号的越南文字,都落在 4 字节 Unicode 区域。服务端看到这类字节序列(比如 \xF0\x9F\x97\xA9),会拒绝写入。
utf8mb4 才是完整 UTF-8 实现,“mb4” 就是 “max bytes 4”。它从 MySQL 5.5.3 引入,8.0 起设为默认,本质是补上本该有的基础能力。
SHOW VARIABLES LIKE 'character%' 全是 utf8mb4 就万事大吉?
不。四个变量全为 utf8mb4 只说明连接层没卡住,不代表数据能正确存取:
-
character_set_server是新建库/表的默认值,不影响已有字段 -
SHOW CREATE TABLE 表名查出来的字段定义才是真实存储编码,可能仍是CHARSET=latin1或CHARSET=utf8 - 哪怕连接和 server 都是
utf8mb4,只要字段本身是utf8,插入四字节字符仍失败 -
init_connect='SET NAMES utf8'在 8.0 下会被静默映射成utf8mb4,但仅作用于会话层,不改变字段定义
改配置文件必须动这三处段落
只在 [mysqld] 段写 character-set-server = utf8mb4 是无效的。MySQL 启动后实际行为由三层协同决定:
-
[mysqld]段:character-set-server = utf8mb4+collation-server = utf8mb4_0900_ai_ci+init_connect='SET NAMES utf8mb4' -
[client]段:default-character-set = utf8mb4(影响mysqldump、mysql命令行等所有客户端工具) -
[mysql]段:default-character-set = utf8mb4(专用于mysql命令行自身,不加可能被忽略)
Windows 用户注意路径:phpEnv 默认在 C:\phpEnv\MySQL\my.ini;宝塔用户要进【软件商店】→ MySQL → 【设置】→ 【配置修改】;Docker 必须挂载自定义 my.cnf 到容器内 /etc/mysql/my.cnf,且权限设为 644,否则静默跳过。
ALTER TABLE ... CONVERT TO CHARACTER SET utf8mb4 容易踩的坑
这条命令看着简单,但实际执行时有几个关键点常被忽略:
- 不会保留原字段的
COLLATION,而是直接套用当前字符集的默认排序规则(utf8mb4_0900_ai_ci),可能导致大小写或重音匹配行为突变 - InnoDB 有索引长度限制(默认 767 字节),
utf8mb4下每个字符最多占 4 字节,所以VARCHAR(255)加索引会超限,需提前确认innodb_large_prefix = ON - 对已含
latin1编码数据的字段执行CONVERT TO,不是“解码再重编码”,而是按字节直接 reinterpret,若原始数据本就是乱码,转换后仍是乱码 - 导出 SQL 文件时若没加
--default-character-set=utf8mb4,文件本身已损毁,再怎么调目标库都没用
真正要改的不是某一个配置项,是整条链路:服务端声明、连接层协商、字段级定义、应用连接串参数(如 JDBC 的 useUnicode=true&characterEncoding=utf8mb4),缺一不可。最容易被忽略的是字段级 CHARACTER SET 和 COLLATION ——它们才是最终决定数据怎么存、怎么比的底层依据。











