MySQL 8.0 默认字符集改为 utf8mb4 是因 latin1 和旧 utf8(utf8mb3)均无法存储中文、Emoji 等 4 字节 Unicode 字符,插入必报 Incorrect string value;utf8mb4 才是完整 UTF-8 实现,需服务端、连接、库表列、排序规则、行格式五层对齐才真正生效。

MySQL 8.0 默认字符集从 latin1 改为 utf8mb4,不是为了“兼容性升级”或“技术演进”,而是因为 latin1 根本存不了中文、Emoji 和大量现代 Unicode 字符——插入直接报 Incorrect string value,这是硬性失败,不是配置没调好。
为什么 latin1 在 2026 年已完全不适用
latin1 只支持单字节编码(0x00–0xFF),能表示的字符仅限西欧语言,连中文、日文、俄文、阿拉伯文都完全无法存储。哪怕客户端发来 UTF-8 编码的汉字字节流(如 E4 B8 AD),服务端也会当成乱码截断或拒绝写入。很多老系统当年用 latin1 是因历史惯性+无多语言需求,但今天用户昵称带 ?、地址含“?田”、评论里有 ?,latin1 就是死路一条。
- 插入
'你好'→ 报错Incorrect string value: '\xE4\xBD\xA0\xE5\xA5\xBD'... - 字段定义为
VARCHAR(100),实际只存下 100 个字节,不是 100 个汉字 -
SHOW CREATE TABLE显示列的CHARACTER SET是latin1,就说明它从物理层就不认识中文
为什么不是改用 utf8(即 utf8mb3)
MySQL 的 utf8 是个历史包袱:它最多只支持 3 字节编码,覆盖范围仅限 Unicode 基本平面(U+0000–U+FFFF)。而 Emoji(如 \xF0\x9F\x98\x80)、扩展汉字(如“?” U+20000)、越南语复合音标等,全在辅助平面,需 4 字节。执行 SHOW CHARSET LIKE 'utf8' 会看到 Maxlen: 3,这就是铁证。
- 插入
'?'→ 同样报Incorrect string value -
utf8在 MySQL 8.0.28+ 已被官方标记为「已弃用」,不能再用于新部署 - 即使你手动设了
character-set-server = utf8,只要客户端或连接层带charset=utf8mb4,MySQL 仍可能静默降级失败
utf8mb4 是唯一能跑通现代应用的字符集
utf8mb4 中的 “mb4” 就是 “max bytes 4”,它是 MySQL 对完整 UTF-8 的唯一合规实现,自 5.5.3 引入,8.0 起设为默认——这不是新增功能,是补上基础能力缺口。但要注意:utf8mb4 生效必须五层对齐:
- 服务端变量:
character_set_server、collation_server - 连接层:
character_set_client、character_set_connection、character_set_results - 库/表/列定义:不能只靠
CONVERT TO CHARACTER SET utf8mb4,必须显式指定COLLATE(如utf8mb4_0900_ai_ci) - 客户端工具配置:比如
[client]段的default-character-set = utf8mb4 - 应用连接参数:JDBC 必须带
&characterEncoding=utf8mb4,Python 的charset='utf8mb4'
漏掉任一环,INSERT INTO t VALUES ('?') 就会失败,或者查出来是 EFBFBD()而不是原始四字节。
容易被忽略的关键点
很多人以为改完 my.cnf 重启就万事大吉,结果上线后用户反馈昵称变问号。真正卡住的往往不是服务端,而是:
- 旧表字段没重定义:ALTER TABLE 只改表默认值,不会自动更新已有列的
CHARACTER SET,得用MODIFY COLUMN或CHANGE COLUMN显式改 - 索引长度超限:
VARCHAR(255)在utf8mb4下理论占 1020 字节,若未开启innodb_large_prefix或未设ROW_FORMAT=DYNAMIC,建索引会静默失败或退化 - 排序规则不一致:新表用
utf8mb4_0900_ai_ci,老表还是utf8mb4_unicode_ci,跨表 JOIN 会触发Illegal mix of collations - 备份恢复链路断裂:mysqldump 默认不带
--default-character-set=utf8mb4,导出的 SQL 文件可能用错编码重放
验证是否真生效,别只看 SHOW VARIABLES,必须实测插入和查询 Emoji,并用 SELECT HEX(c) 确认返回的是原始四字节序列。


















