MySQL 5.7+ 启动时默认字符集不是 utf8mb4?
是的,默认不是。MySQL 5.7 默认
character_set_server是
latin1,
collation_server是
latin1_swedish_ci,哪怕你建库时指定了
utf8mb4,新创建的数据库、表、列仍可能继承服务端默认值,导致插入中文乱码、emoji 存不进去、ORDER BY 排序异常等问题。
根本原因在于:MySQL 的字符集生效是分层的(服务器 → 数据库 → 表 → 列),且客户端连接时若未显式指定,会按服务端默认值协商编码,造成「看起来能存,实际传输过程已损坏」。
检查当前设置:SHOW VARIABLES LIKE 'character\_set\_%';和
SHOW VARIABLES LIKE 'collation\_%';临时修改(重启失效):
SET GLOBAL character_set_server = 'utf8mb4'; SET GLOBAL collation_server = 'utf8mb4_unicode_ci';真正生效必须写入配置文件并重启
mysqld
my.cnf 中该在哪几个段落写 charset 配置?
必须同时覆盖
[client]、
[mysql]、
[mysqld]三个段落,缺一不可。只改
[mysqld]只影响服务端,客户端(如 mysql 命令行、PHP PDO)仍可能用错编码握手。
[client] default-character-set = utf8mb4 [mysql] default-character-set = utf8mb4 [mysqld] character-set-server = utf8mb4 collation-server = utf8mb4_unicode_ci init_connect = 'SET NAMES utf8mb4' skip-character-set-client-handshake = FALSE
init_connect确保普通用户连接后自动执行
SET NAMES,但对
root或带
SUPER权限用户无效(安全限制)
skip-character-set-client-handshake = FALSE强制服务端以配置值响应客户端的编码协商请求(默认为 TRUE,即允许客户端“自说自话”) 注意:MySQL 8.0+ 已废弃
init_connect对 SUPER 用户的限制,但兼容性起见仍建议保留
建库建表时还要再指定 utf8mb4 吗?
要,而且必须显式指定。即使服务端已设为
utf8mb4,新建数据库若不声明,仍可能继承旧默认值(尤其升级或迁移环境时)。 创建数据库:
CREATE DATABASE db_name CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;创建数据表:
CREATE TABLE t (c VARCHAR(100)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;已有表转换:
ALTER TABLE t CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;(注意:该语句会重建表,大表慎用) 特别注意
VARCHAR字段长度:utf8mb4 下每个字符最多占 4 字节,InnoDB 单行最大 65535 字节限制下,
VARCHAR(255)实际占用字节数翻倍,极端情况下可能触发
Row size too large错误
PHP/Python 连接时为什么还是乱码?
因为客户端驱动没传对编码参数,服务端配置只是基础,连接时的「协商」环节才是关键。
PHP mysqli:$mysqli = new mysqli($host, $user, $pass, $db); $mysqli->set_charset('utf8mb4'); 或在 DSN 中加 ;charset=utf8mb4PHP PDO:
new PDO($dsn, $user, $pass, [PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8mb4']);Python PyMySQL:
conn = pymysql.connect(..., charset='utf8mb4')Node.js mysql2:
{ charset: 'utf8mb4' } 选项必须显式传入
错误典型表现:、???、插入成功但 SELECT 出来是空格或问号——大概率是连接层编码没对齐 实际部署中最容易漏掉的是客户端配置段落和应用层连接参数,服务端改完以为万事大吉,结果应用一连就出问题。字符集这事,得从 my.cnf、建表语句、连接初始化、甚至前端 HTTP 头(Content-Type charset)全链路对齐才稳。
