MySQL插入中文乱码本质是客户端、连接层、表结构三层字符集不一致,必须统一为utf8mb4:SET NAMES utf8mb4设连接层,表/列需显式定义CHARSET=utf8mb4,my.cnf中配置character-set-server=utf8mb4并重启。

MySQL 插入数据乱码,本质是客户端、连接层、表结构三层字符集不一致
乱码不是“没设 UTF8”这么简单。常见现象是:插入中文显示为 ??? 或 æäº›å,但 SELECT 查出来又“看起来正常”——这说明数据已损坏,不是显示问题。关键要确认三处是否统一为 utf8mb4(不是过时的 utf8):character_set_client、character_set_connection、character_set_results,以及表/列的 CHARACTER SET 和 COLLATION。
执行 SET NAMES utf8mb4 仅对当前连接生效,且必须在 INSERT 前调用
SET NAMES utf8mb4 是快捷方式,等价于同时设置 client/connection/results 为 utf8mb4。但它只影响当前连接生命周期,断开重连就失效。很多 ORM(如 Python 的 pymysql、Java 的 JDBC)默认不自动发这条命令,需手动配置或显式执行。
- PHP mysqli:连接后立即执行
$mysqli->query("SET NAMES utf8mb4") - Node.js mysql2:在连接配置中加
charset: 'utf8mb4',比运行时SET NAMES更可靠 - 命令行 mysql 客户端:启动时加
--default-character-set=utf8mb4,或登录后手动输SET NAMES utf8mb4
表和列必须用 utf8mb4,不能只靠连接层设置
即使连接层全设成 utf8mb4,如果表定义仍是 CHARACTER SET utf8(MySQL 中实际是 utf8mb3),插入四字节 emoji 或某些生僻汉字仍会截断或转成问号。验证方式:SHOW CREATE TABLE your_table,检查输出中是否含 DEFAULT CHARSET=utf8mb4 和列定义带 COLLATE utf8mb4_unicode_ci。
- 修改现有表:用
ALTER TABLE your_table CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci - 新建表务必显式指定:
CREATE TABLE t (c VARCHAR(100)) CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci - 注意:
utf8在 MySQL 8.0+ 已是别名,但低版本仍指utf8mb3,必须写死utf8mb4
my.cnf 配置文件里 default-character-set 已被弃用,改用 character-set-server
MySQL 5.5.3+ 开始,[client] 和 [mysql] 段的 default-character-set 被标记为废弃,部分版本会报 warning;真正起效的是 character-set-server(服务端默认字符集)和 collation-server。但要注意:它只影响新创建的数据库/表的默认值,不影响已有对象。
- 推荐配置(my.cnf 中):
[mysqld] character-set-server = utf8mb4 collation-server = utf8mb4_unicode_ci [client] default-character-set = utf8mb4 [mysql] default-character-set = utf8mb4
- 改完必须重启 MySQL,且需验证:
SHOW VARIABLES LIKE 'character_set%'和SHOW VARIABLES LIKE 'collation%' - 即使全局配了,应用层仍建议显式
SET NAMES utf8mb4或用连接参数,避免依赖服务器默认值
utf8mb4 要求对应字段的 MAX_LENGTH 实际占用字节数翻倍(比如 VARCHAR(255) 在 utf8mb4 下最多存 255 个四字节字符,但索引长度限制仍按字节算,可能触发 Specified key was too long 错误)。改字符集前,先检查索引字段长度是否超标。


















