根本原因是客户端、服务端、连接层三者字符集不一致,set names utf8mb4仅临时修改当前会话连接层设置;需统一配置my.cnf/my.ini中[client]、[mysql]、[mysqld]段的字符集,并在建库建表时显式指定utf8mb4,同时确保客户端驱动支持并正确初始化。

MySQL 客户端连接时显示乱码,SET NAMES utf8mb4 临时有效但重启就失效
根本原因是客户端、服务端、连接层三者字符集不一致,而 SET NAMES utf8mb4 只改当前会话的连接层设置,不影响后续新连接。真正要管住所有连接,得从配置源头下手。
- 修改
my.cnf(Linux)或my.ini(Windows),在[client]、[mysql]、[mysqld]三个段落下分别加default-character-set = utf8mb4(旧版本)或character-set-client-handshake = FALSE+collation-server = utf8mb4_unicode_ci(推荐) -
[mysqld]段必须设character-set-server = utf8mb4,否则新建库默认还是latin1 - 注意:MySQL 8.0+ 已弃用
default-character-set,只认character-set-server和collation-server;如果配置了已废弃项,启动时会报 warning 但不会失败,容易误以为生效了
建库/建表时没指定字符集,导致插入中文报错 Incorrect string value
这是典型的 utf8mb4 未穿透到表结构层——即使服务端全局设对了,建库建表不显式声明,依然可能沿用老默认值。
- 创建数据库时务必写全:
CREATE DATABASE db_name CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; - 已有库可修改:
ALTER DATABASE db_name CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci; - 建表时别省略:
CREATE TABLE t (c VARCHAR(10)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; - 特别注意:MySQL 的
utf8实际是阉割版(最多 3 字节),不支持 emoji 和部分生僻汉字;必须用utf8mb4,且客户端驱动也要支持(如 JDBC 需加?characterEncoding=utf8mb4)
PHP/Python 连接 MySQL 后仍乱码,mysqli_set_charset() 或 conn.set_character_set('utf8mb4') 不起作用
代码层设置晚于连接建立,如果连接握手时服务端按旧配置发了 latin1,再调函数也救不回来。
- PHP mysqli:必须在
new mysqli()后立刻调$mysqli->set_charset('utf8mb4'),不能等执行 SQL 再设 - Python PyMySQL:初始化
connect()时直接传参charset='utf8mb4',比事后调set_character_set()更可靠 - JDBC URL 示例:
jdbc:mysql://localhost:3306/db?useUnicode=true&characterEncoding=utf8mb4&serverTimezone=UTC—— 缺少useUnicode=true会导致characterEncoding被忽略 - 验证是否真生效:连上后执行
SELECT @@character_set_client, @@character_set_connection, @@character_set_results;,三者都应为utf8mb4
MySQL 8.0 升级后应用突然乱码,SHOW VARIABLES LIKE 'character%' 显示全是 utf8mb4 却还是不对
大概率是认证插件变更引发的隐性兼容问题:MySQL 8.0 默认用 caching_sha2_password,某些老客户端(如 MySQL 5.7 客户端、旧版 PHP 扩展)无法正确协商字符集。
- 临时验证:登录后执行
SELECT user, host, plugin FROM mysql.user WHERE user='your_user';,若 plugin 是caching_sha2_password,就先改成mysql_native_password - 改法:
ALTER USER 'your_user'@'%' IDENTIFIED WITH mysql_native_password BY 'password'; - 更彻底的解法是升级客户端驱动,比如 PHP 7.4+、PyMySQL 0.10+ 均原生支持
caching_sha2_password,但需确认连接参数里没硬编码旧协议 - 这个坑不报错、不告警,只默默降级字符集协商,所以必须手动查
@@character_set_client确认











