mysql的utf8实为utf8mb3别名,仅支持最多3字节编码,无法存储emoji(如?)和四字节unicode字符(如「?」),故报incorrect string value错误;utf8mb4才符合rfc 3629,支持1–4字节完整utf-8。

MySQL 的 utf8 不是真正的 UTF-8,它存不了 emoji 和很多生僻汉字
为什么 utf8 会报 Incorrect string value 错误
MySQL 的 utf8 实际是 utf8mb3 的别名,只支持最多 3 字节编码。像 ?(U+1F603)、中文扩展 B 区字「?」(U+20000)、越南语带多重音符的字符,都需 4 字节 UTF-8 编码,utf8mb3 直接拒绝写入,抛出 Incorrect string value。
常见错误现象:
- 插入含 emoji 的订单备注、用户昵称时被截断或报错
- 广东、福建等地身份证姓名含生僻字(如「堃」「煊」某些变体)入库失败
- APP 端发来的消息看似正常,后端日志里却显示乱码或空值
utf8mb4 是 MySQL 唯一严格遵循 RFC 3629 的 UTF-8 实现
它支持 1–4 字节编码,覆盖全部 Unicode 码位(U+0000 至 U+10FFFF)。这不是“多支持几个表情”那么简单——它是存储层对现代文本输入的真实适配。
关键差异点:
-
VARCHAR(255)在utf8mb4下最大占 1020 字节(255 × 4),而utf8mb3是 765 字节(255 × 3);InnoDB 索引前缀长度限制(如 767/3072 字节)必须重算 - 排序规则必须匹配:MySQL 8.0 默认用
utf8mb4_0900_ai_ci,它正确处理ß = ss、ä = a等语言逻辑;utf8mb4_general_ci已弃用,别混用 -
init_connect='SET NAMES utf8'会被静默映射为utf8mb4,但**不改变已有字段定义**——表结构仍是utf8mb3,照样存失败
怎么确认你的环境真能存 emoji,而不是“看起来可以”
别只查 SHOW VARIABLES LIKE 'character_set%',那些只反映连接配置,和字段无关。
实测步骤:
- 执行
INSERT INTO t (s) VALUES (0xF09F988A);(这是?的原始 UTF-8 四字节序列),看是否报错 - 用
SHOW CREATE TABLE t;确认每个字段明确写着CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci - 如果已有
utf8表,运行ALTER TABLE t CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;——注意:大表会锁表、重建索引、吃磁盘空间
最容易被忽略的一点:ORM 框架(Django、Rails、MyBatis)可能默认发 SET NAMES utf8,即使数据库服务端设了 utf8mb4,连接层仍可能降级。必须在框架配置里显式指定字符集为 utf8mb4,不能依赖别名或默认值。











