mysql 8.0 默认用 utf8mb4 是因旧 utf8(utf8mb3)仅支持3字节编码,无法存储表情符号等4字节 unicode 字符;utf8mb4 才是完整 utf-8 实现,需客户端、连接、库表列、排序规则、行格式五层对齐才真正生效。

MySQL 8.0 默认用 utf8mb4 不是因为“更先进”,而是因为旧的 utf8(实际是 utf8mb3)根本存不了表情符号——它连基本的 Unicode 四字节字符都不支持,一插就报 Incorrect string value。
MySQL 的 utf8 根本不是真正的 UTF-8
MySQL 早期实现的 utf8 是个历史别名,最多只处理 3 字节编码,覆盖范围仅限 Unicode BMP 平面(U+0000–U+FFFF)。而常见 Emoji 如 ?、?、??,以及很多生僻汉字(如“?”)、越南语复合音标,都落在辅助平面(U+10000 起),需 4 字节编码。服务端看到 \xF0\x9F\x92\x95 这类字节流,直接拒绝写入。
utf8mb4 中的 “mb4” 就是 “max bytes 4”,它是 MySQL 对完整 UTF-8 的唯一合规实现,自 5.5.3 引入,8.0 起设为默认,属于补基础能力,不是新增功能。
utf8mb4 生效必须五层对齐,缺一不可
只改 character_set_server = utf8mb4 看似生效,但插入 Emoji 仍失败,大概率卡在以下任一环节:
- 客户端配置缺失:
[client]和[mysql]段没配default-character-set = utf8mb4,导致mysql命令行工具或备份脚本仍用utf8解码 - 连接握手被绕过:没加
character-set-client-handshake = FALSE,客户端(比如 JDBC 参数里带characterEncoding=utf8)声明的旧字符集会覆盖服务端设置 - 已有对象未升级:老库/表/列的
CHARSET和COLLATION仍是utf8或latin1,CONVERT TO CHARACTER SET utf8mb4必须显式执行,且要连带指定COLLATE - 排序规则不一致:8.0 默认用
utf8mb4_0900_ai_ci,而老表可能是utf8mb4_general_ci,跨表 JOIN 或ORDER BY会触发Illegal mix of collations - InnoDB 行格式限制:若字段是
VARCHAR(255)且建了索引,utf8mb4下理论占 1020 字节,超默认 767 字节上限;需确认innodb_large_prefix = ON且表使用ROW_FORMAT=DYNAMIC
验证是否真支持 Emoji,不能只看变量
执行 SHOW VARIABLES LIKE 'character\_set\_%' 全是 utf8mb4 只说明服务端“声称”支持,不代表能用。必须实测:
- 用
mysql客户端连上去,执行INSERT INTO t (c) VALUES ('?');,不报错才算过第一关 - 再查一遍:
SELECT HEX(c), c FROM t;,确认返回的是F09F988E(即原始四字节),而不是截断成EFBFBD()或报错 - 如果用 JDBC,确保驱动 ≥ 5.1.13,连接串含
useUnicode=true&characterEncoding=utf8mb4,且去掉可能冲突的characterEncoding=utf8
最容易被忽略的是字段级定义:即使库和表都改了,某个 VARCHAR 字段若建表时硬编码了 CHARACTER SET utf8,CONVERT TO 可能跳过它——得用 MODIFY COLUMN 显式重写。











