根本原因是mysql的utf8实为utf8mb3,仅支持3字节编码,无法存储emoji或部分生僻汉字等4字节utf-8字符;必须客户端、连接层、表/列、服务端四层字符集全部统一为utf8mb4。

MySQL插入中文报错 Incorrect string value 的根本原因
这个错误不是 MySQL 拒绝中文,而是客户端传入的字节序列无法被当前字段的字符集(通常是 utf8)合法解码。MySQL 的 utf8 实际是阉割版,最多只支持 3 字节 UTF-8 编码(即不支持 emoji 和部分生僻汉字),而真正的 UTF-8(如汉字“?”、emoji “?”)需要 4 字节。当应用发送了 4 字节 UTF-8 数据,但列用的是 utf8(而非 utf8mb4),就会触发该错误。
关键判断点:查一下出问题字段的字符集和排序规则
SHOW CREATE TABLE `your_table`;如果看到
CHARSET=utf8 或 COLLATE=utf8_general_ci,基本就是它了。
必须同时修改的 4 个层级(缺一不可)
MySQL 的字符集生效依赖「客户端 → 连接 → 表/列 → 服务端」全链路一致,任一环节卡在 utf8 都会失败:
- 服务端配置:确保
my.cnf 中设置了 character-set-server = utf8mb4,并重启 mysqld(仅改变量不重启无效)
- 数据库/表/列级:执行
ALTER DATABASE db_name CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci;,再对每张表、每个文本字段单独执行 MODIFY COLUMN col_name VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
- 连接层:应用建立连接时,必须显式指定字符集,例如 PHP PDO 要加
charset=utf8mb4 到 DSN;Python PyMySQL 要传 charset='utf8mb4' 参数;Java JDBC URL 加 ?characterEncoding=utf8mb4
- 客户端工具(如 Navicat、MySQL CLI):也要手动设置连接字符集,CLI 可执行
SET NAMES utf8mb4;,但更推荐在配置文件中设默认值
utf8mb4_unicode_ci 和 utf8mb4_0900_ai_ci 怎么选
MySQL 8.0+ 默认用 utf8mb4_0900_ai_ci,它比 utf8mb4_unicode_ci 更准确(尤其对德语 ß、西班牙语重音等),且性能略优。但如果你的应用依赖旧版排序行为(比如某些 PHP ORDER BY 结果突变),可继续用 utf8mb4_unicode_ci。二者都完全支持 4 字节 UTF-8,功能上无差别,选哪个不影响 Incorrect string value 是否出现。
my.cnf 中设置了 character-set-server = utf8mb4,并重启 mysqld(仅改变量不重启无效)ALTER DATABASE db_name CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci;,再对每张表、每个文本字段单独执行 MODIFY COLUMN col_name VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
charset=utf8mb4 到 DSN;Python PyMySQL 要传 charset='utf8mb4' 参数;Java JDBC URL 加 ?characterEncoding=utf8mb4
SET NAMES utf8mb4;,但更推荐在配置文件中设默认值utf8mb4_unicode_ci 和 utf8mb4_0900_ai_ci 怎么选
MySQL 8.0+ 默认用 utf8mb4_0900_ai_ci,它比 utf8mb4_unicode_ci 更准确(尤其对德语 ß、西班牙语重音等),且性能略优。但如果你的应用依赖旧版排序行为(比如某些 PHP ORDER BY 结果突变),可继续用 utf8mb4_unicode_ci。二者都完全支持 4 字节 UTF-8,功能上无差别,选哪个不影响 Incorrect string value 是否出现。
注意:utf8mb4_bin 是严格字节比较,不推荐用于通用文本字段,会导致大小写敏感、无法正确排序中文
验证是否真正生效的三步检查法
别只看建表语句,要逐层确认实际生效值:
- 查服务端全局变量:
SHOW VARIABLES LIKE 'character_set%'; —— 关注 character_set_server 和 collation_server 必须是 utf8mb4 相关
- 查当前连接:
SHOW VARIABLES LIKE 'character_set_client'; SHOW VARIABLES LIKE 'collation_connection'; —— 二者也必须是 utf8mb4,否则即使表是 utf8mb4,连接层已转码失败
- 查字段定义:
SHOW FULL COLUMNS FROM your_table LIKE 'your_column'; —— 确认 Collation 列显示为 utf8mb4_unicode_ci 或类似,而非 utf8_general_ci
很多问题卡在第二步:应用连上去了,但没发 SET NAMES utf8mb4,导致连接层还是 utf8,这时候改表也没用。
SHOW VARIABLES LIKE 'character_set%'; —— 关注 character_set_server 和 collation_server 必须是 utf8mb4 相关SHOW VARIABLES LIKE 'character_set_client'; SHOW VARIABLES LIKE 'collation_connection'; —— 二者也必须是 utf8mb4,否则即使表是 utf8mb4,连接层已转码失败SHOW FULL COLUMNS FROM your_table LIKE 'your_column'; —— 确认 Collation 列显示为 utf8mb4_unicode_ci 或类似,而非 utf8_general_ci
最常被忽略的是连接层字符集——它不继承表定义,也不继承服务端默认值,必须由客户端显式声明或通过配置强制统一。











