mysql乱码根源在于服务端字符集未正确设为utf8mb4:需修改my.ini中[mysqld]段的character-set-server=utf8mb4和collation-server=utf8mb4_unicode_ci,重启服务,并手动转换旧库表字符集,同时php连接须显式声明charset=utf8mb4。

乱码不是“显示问题”,而是 MySQL 服务端默认字符集没改对。只改 PHP 或网页编码、只在客户端加 SET NAMES utf8mb4,都没用——数据存进去就错了,后面全白搭。
确认当前 MySQL 字符集是否真为 utf8mb4
别猜,直接连进 MySQL 命令行执行:
mysql -u root -p SHOW VARIABLES LIKE 'character_set_server'; SHOW VARIABLES LIKE 'collation_server';
如果返回是 latin1 或 utf8(注意:MySQL 的 utf8 是 utf8mb3,不支持 emoji),说明服务端根本没生效。
-
character_set_server必须是utf8mb4,否则新建库表默认就错 -
collation_server应为utf8mb4_unicode_ci或utf8mb4_general_ci,不能留空或为latin1_swedish_ci - 不要只看
character_set_client或character_set_connection,它们受客户端影响大,不可靠
修改 XAMPP 的 my.ini(不是 my.cnf)
XAMPP 在 Windows 下实际加载的是 C:\xampp\mysql\bin\my.ini,不是 conf\my.cnf。编辑这个文件,在 [mysqld] 段下写死两行:
[mysqld] character-set-server = utf8mb4 collation-server = utf8mb4_unicode_ci
务必删掉所有带 default-character-set 的行(该参数已废弃,且只在 [client] 段有效,对服务端无效)。
- 不要在
[client]或[mysql]段写character-set-server—— 它只对服务端生效 - 不要加
init_connect = 'SET NAMES utf8mb4',它无法覆盖服务端默认值,还可能被权限限制拦截 - 改完必须用 XAMPP 控制面板「停止 → 启动」MySQL,不能只刷新页面或重启 Apache
已有数据库和表必须手动转 utf8mb4
改完配置并重启,只影响新创建的库表。旧库旧表仍用 latin1 或 utf8mb3,导出/查询时照样乱码。
逐个执行:
ALTER DATABASE `your_db_name` CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci; ALTER TABLE `your_table_name` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
- 执行前务必备份,
CONVERT TO会重建表,大数据量可能锁表 - 如果报错
ERROR 1071 (42000),说明某字段索引长度超限(如 varchar(255) + utf8mb4 → 实际占 1020 字节),需先缩小字段长度或改用前缀索引 - 视图、存储过程等对象不自动继承新字符集,需单独
ALTER或重建
PHP 连接也得显式声明 utf8mb4
即使服务端设对了,PHP 默认仍可能走 utf8 连接协议,导致插入/读取时二次转换出错。
- 用
mysqli:连接后立刻调用mysqli_set_charset($conn, 'utf8mb4'),别依赖SET NAMES - 用
PDO:DSN 中必须带;charset=utf8mb4,例如mysql:host=localhost;dbname=test;charset=utf8mb4 - phpMyAdmin 需同步修改
config.inc.php,在$cfg['Servers'][$i]['charset']设为'utf8mb4'
最容易被忽略的是:改完服务端配置后,忘了处理旧数据的字符集转换——哪怕所有配置都对了,老表里存的还是 latin1 编码的字节,查出来就是乱码,这点没法绕过去。











