mysql 8.0 默认用 utf8mb4 是因旧 utf8(即 utf8mb3)仅支持最多3字节unicode字符,无法存储 emoji、生僻汉字等4字节字符,插入会报 incorrect string value;utf8mb4 才是完整 utf-8 实现,自 5.5.3 引入,8.0 起设为默认以补全基础能力。

MySQL 8.0 默认用 utf8mb4,不是为了“升级感”,而是 latin1 和 MySQL 自己的 utf8 都没法存 emoji、生僻汉字、某些东亚符号——硬要存,直接报 Incorrect string value。
为什么 utf8 在 MySQL 里不能存 emoji
MySQL 的 utf8 是个历史包袱:它只支持最多 3 字节的 Unicode 编码(即 utf8mb3),而 emoji(如 ?)、中文生僻字(如 “?”)、越南语带多重变音符号的字,都落在 Unicode 四字节区(U+10000–U+10FFFF)。服务端看到这类字符,会拒绝写入,抛出 Incorrect string value: '\xF0\x9F\x97\xA9' for column ... 这类错误。
真正兼容完整 UTF-8 的是 utf8mb4,“mb4” 就是 “max bytes 4” 的意思。MySQL 5.5.3 引入它,8.0 直接设为默认,不是功能新增,而是补上本该有的基础能力。
升级后老表没变,但连接和新建对象全“悄悄升级”了
从 5.7 升到 8.0,SHOW VARIABLES LIKE 'character_set_server' 返回 utf8mb4,看起来万事大吉——但 SHOW CREATE TABLE 表名 一查,字段可能还是 CHARSET=latin1 或 CHARSET=utf8。这是因为:
- 已有库/表/列的字符集不会自动改,只影响新创建的对象
-
init_connect='SET NAMES utf8'在 8.0 下会被服务端静默映射成utf8mb4,但若字段本身是utf8,插入四字节字符仍失败 - 拷贝数据文件到 8.0 实例时,系统可能把旧
utf8列自动映射为utf8mb4_general_ci,但底层存储字节没重编码,乱码风险仍在
真正要改的不是配置,是整条链路的声明与转换
光改 my.cnf 里的 character-set-server = utf8mb4 不够,必须对齐五处:
- 服务端:
character_set_server和collation_server - 数据库级:
CREATE DATABASE ... CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci - 表级:
ALTER TABLE 表名 CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci - 连接层:应用连接串必须显式指定
charset=utf8mb4(如 JDBC 的useUnicode=true&characterEncoding=utf8mb4) - InnoDB 限制:若表有长文本索引(如
VARCHAR(255)加索引),需确认innodb_large_prefix = ON,否则ALTER TABLE可能因行大小超限失败
特别注意:对已含 latin1 编码数据的字段执行 CONVERT TO CHARACTER SET utf8mb4,不等于“解码再重编码”,MySQL 默认只是改元数据声明——如果原始数据是 latin1 编码的德语 ä(字节 E4),直接转成 utf8mb4 字段后,客户端按 utf8mb4 解释 E4,会得到乱码或问号。这种场景必须先确认原始编码,再用 CONVERT ... USING 显式转码,或导出重导入。
容易被忽略的兼容性细节
utf8mb4_0900_ai_ci 是 8.0 默认排序规则,它比 utf8mb4_unicode_ci 更精确(比如对德语 ß 和 ss 的等价处理),但部分老应用依赖旧排序行为。如果发现 ORDER BY 或 WHERE 比较结果异常,别急着换回 _unicode_ci,先查 SHOW COLLATION LIKE 'utf8mb4%' 确认当前默认是否被覆盖,以及应用是否在建表时硬编码了 collation。











