必须四层全设为utf8mb4:数据库、表、字段、连接缺一不可;仅alter database无效,因旧表字符集仍为utf8,字段未显式声明utf8mb4,连接层未设characterencoding=utf8mb4,均会导致error 1366。

必须把数据库、表、字段、连接这四层全设成 utf8mb4,缺一不可;只改其中一层,依然会报 ERROR 1366 (HY000): Incorrect string value。
为什么改了数据库字符集还是报错?
常见错觉是“只要 ALTER DATABASE xxx CHARACTER SET utf8mb4 就完事了”,但实际插入失败往往卡在更下游的位置:
- 表本身字符集仍是
utf8(哪怕数据库是utf8mb4,新建表也不会自动继承) - 字段定义没显式指定字符集,比如
content VARCHAR(255)没写CHARACTER SET utf8mb4,就会沿用表默认,而旧表默认可能还是utf8 -
SHOW CREATE TABLE看到的DEFAULT CHARSET=utf8就是铁证
如何一次性把表和字段都升级到 utf8mb4?
别依赖图形工具点几下——Navicat 或 DBeaver 的 UI 修改有时只改表级,漏掉字段。直接跑 SQL 最可靠:
ALTER TABLE users CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
这条命令会同时改:表默认字符集、所有 CHAR/VARCHAR/TEXT 字段的字符集、以及对应索引。但注意:
- 如果字段用了
utf8mb4_bin这类 collation,CONVERT TO会覆盖成utf8mb4_unicode_ci,需手动再调 - 有全文索引的表,
CONVERT TO可能失败,得先DROP FULLTEXT INDEX,改完再重建 - 大表执行会锁表,生产环境建议在低峰期做,或用
pt-online-schema-change
JDBC 连接字符串漏了这个参数就白配
即使数据库和表全设对了,Java 应用仍可能报错,因为 MySQL 驱动默认按 utf8 解析连接 —— 它根本不知道你存的是 4 字节 Emoji。必须显式声明:
在 JDBC URL 末尾加上:?useUnicode=true&characterEncoding=utf8mb4
例如:jdbc:mysql://localhost:3306/mydb?useUnicode=true&characterEncoding=utf8mb4
不加这个,驱动会把 \xF0\x9F\x98\x84 当作非法 utf8 字节流直接拒掉,错误堆栈里一定带 Incorrect string value。
my.cnf 里这三行配置最容易被忽略
很多团队只改了 [mysqld] 下的 character-set-server,但客户端连接时仍可能退化回 utf8。必须补全:
[mysqld] character-set-server = utf8mb4 collation-server = utf8mb4_unicode_ci init_connect = 'SET NAMES utf8mb4' [client] default-character-set = utf8mb4
其中 init_connect 是关键:它让每个新连接自动执行 SET NAMES utf8mb4,避免应用层漏发该语句。重启 MySQL 才生效。
真正麻烦的不是改配置,而是验证——SHOW VARIABLES LIKE 'character_set%' 要看到 client、connection、results、server 全是 utf8mb4;SHOW CREATE TABLE 里字段定义要带 CHARACTER SET utf8mb4;连上之后执行 SELECT CHARSET('?'); 返回 utf8mb4 才算闭环。











