mysql 8.0 默认字符集为utf8mb4,但需完整配置client、mysql、mysqld三段并验证5个字符集变量全为utf8mb4,同时升级旧库表、显式声明客户端charset,否则仍会中文乱码。

MySQL 8.0 默认字符集确实是 utf8mb4,但**仅靠“默认”无法避免中文乱码**——绝大多数乱码问题都出在配置没覆盖全链路,或者重启后根本没生效。
my.cnf 必须同时配齐 client、mysql、mysqld 三段
只改 [mysqld] 段的 character-set-server 是最常见错误。MySQL 启动时会读多个配置段,缺一不可:
-
[client]:影响所有客户端工具(mysql、mysqldump),必须加default-character-set = utf8mb4 -
[mysql]:专用于mysql命令行客户端,也必须加default-character-set = utf8mb4(否则你敲mysql -u root进去还是 latin1) -
[mysqld]:服务端核心配置,至少要写这两行:character-set-server = utf8mb4collation-server = utf8mb4_0900_ai_ci - 别漏掉
skip-character-set-client-handshake = OFF—— 设为ON会强制忽略客户端声明的字符集,JDBC 或 Python 连接时加了charset=utf8mb4也白搭
重启后必须验证全部 5 个关键变量
执行 SHOW VARIABLES LIKE 'character\_set%'; 后,只看 character_set_server 是不够的。真正决定中文能否正常流转的是这五个值是否全为 utf8mb4:
-
character_set_client:你发的 SQL 里中文怎么被 MySQL 读(比如存储过程里的注释) -
character_set_connection:SQL 解析中间转换用的编码 -
character_set_database:当前库的默认字符集(建库时指定,可被ALTER DATABASE改) -
character_set_results:查出来的结果怎么返回给你(比如SELECT '你好'显示成问号就卡在这) -
character_set_server:服务端默认值,影响新建库/表
任意一个不是 utf8mb4,链路就断了。Linux 下常用 sudo systemctl restart mysqld,Windows 要进服务管理器手动重启,reload 不生效。
已有数据库和表不能靠配置文件自动升级
配置文件改完只管新库新表。老库老表字段仍是旧字符集,插入中文可能报 Incorrect string value 或存成问号:
- 先改库:
ALTER DATABASE db_name CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci; - 再改表:
ALTER TABLE table_name CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci; - 如果报错
ERROR 1071 (42000)(索引过长),说明原VARCHAR(255)在utf8mb4下超限(4 字节 × 255 > 767 字节),得先收缩:ALTER TABLE table_name MODIFY column_name VARCHAR(191) ... - 别跳过备份——
CONVERT TO是 DDL 操作,锁表且不可回滚
应用连接字符串必须显式声明 charset
即使服务端全配对了,PHP、Python、Java 这些客户端不主动说“我要 utf8mb4”,MySQL 就按默认(常是 latin1)处理:
- PHP PDO:
$pdo = new PDO("mysql:host=localhost;charset=utf8mb4", ...) - Python PyMySQL:
connect(..., charset="utf8mb4") - Java JDBC:
jdbc:mysql://localhost:3306/db?characterEncoding=utf8mb4&useUnicode=true - Node.js mysql2:
{ charset: 'UTF8MB4_GENERAL_CI' }(注意大小写和下划线)
特别注意:MySQL 8.0 默认认证插件是 caching_sha2_password,旧驱动可能连不上,此时要配合 ?serverTimezone=UTC 和 charset 一起设,否则乱码+连接失败双杀。
最容易被忽略的是 [mysql] 段配置和 character_set_client 的验证——很多人改完以为好了,结果用命令行建了个带中文注释的存储过程,回头 SHOW CREATE PROCEDURE 一看全是问号,就是这一环断了。











