MySQL 8.0 默认用 utf8mb4 是因原 utf8(实为 utf8mb3)仅支持 3 字节 Unicode 字符,无法存储 Emoji 等 4 字节字符,插入会报 Incorrect string value;必须逐层升级数据库、表、列字符集与排序规则,并确保客户端连接声明 charset=utf8mb4,同时启用 innodb_large_prefix 等配套参数。

MySQL 8.0 默认用 utf8mb4 是因为 utf8 根本存不了 Emoji
MySQL 的 utf8 不是真正的 UTF-8,它最多只支持 3 字节字符(即 Unicode BMP 平面内字符),而 Emoji 如 ?、?、?? 都落在辅助平面(U+10000 起),编码为 4 字节。一插就报错:Incorrect string value: '\xF0\x9F\x92\x95' for column ...。这不是应用或驱动的问题,是 MySQL 自己的 utf8 实现从根上就不支持——它只是个历史别名,等价于 utf8mb3,且已在 MySQL 8.0.28+ 中被明确标记为「已弃用」。
utf8mb4 要生效,光改 server 默认值远远不够
只在 [mysqld] 里配 character-set-server = utf8mb4,只能保证新库默认用对;已有库、表、列仍保持旧字符集,插入 Emoji 依然失败。必须逐层确认并升级:
- 数据库级:
ALTER DATABASE db_name CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci; - 表级:
ALTER TABLE tbl_name CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; - 字段级(尤其
VARCHAR):若原字段定义含CHARACTER SET utf8,需显式重写为utf8mb4,否则CONVERT TO可能跳过 - 连接层:客户端连接时必须声明
charset=utf8mb4(JDBC 加?useUnicode=true&characterEncoding=utf8mb4),否则即使服务端设对了,中间握手仍按旧规则解码
改 utf8mb4 后 innodb_large_prefix 和索引长度容易翻车
MySQL 5.7 默认关闭 innodb_large_prefix,InnoDB 单列索引长度上限为 767 字节。而 utf8mb4 下,一个 VARCHAR(255) 字段理论最大占 255×4 = 1020 字节,超限直接建索引失败,报错:Specified key was too long。解决方案不是砍字段长度,而是:
- 确保
innodb_file_format = Barracuda且innodb_file_per_table = ON - 开启
innodb_large_prefix = ON(MySQL 5.7.7+ 默认已开,但低版本或自定义配置可能关着) - 建表时显式指定行格式:
ROW_FORMAT=DYNAMIC或ROW_FORMAT=COMPRESSED
漏掉任一条件,ALTER TABLE ... CONVERT TO 可能静默失败,表结构看似改了,实际字段仍是 utf8 编码。
移动端表情入库失败,八成卡在 JDBC 连接参数或驱动版本
即使服务端全配对了,Java 应用仍报 Incorrect string value,大概率是 JDBC 层没跟上。关键点:
- 驱动必须用
mysql-connector-java 5.1.13+或8.0.0+(旧版对utf8mb4支持不完整) - 连接 URL 必须带
useUnicode=true&characterEncoding=utf8mb4,不能只写characterEncoding=utf8 - Spring Boot 2.4+ 默认自动加
characterEncoding=utf8mb4,但若手动覆盖了url,这个自动行为会被绕过 - MyBatis 等 ORM 一般不干预编码,问题一定出在数据源初始化阶段
最隐蔽的坑:某些老项目用 HikariCP + 自定义 dataSourceProperties,把 characterEncoding 写成 utf8,看着像对的,实则无效。

















