必须在创建存储过程前执行SET NAMES utf8mb4,否则中文注释和字面量会因character_set_client错误导致永久性乱码;需同步配置my.cnf的client[mysqld]三段并重启服务,应用连接也须显式指定charset=utf8mb4。

创建存储过程前必须执行 SET NAMES utf8mb4
存储过程里的中文注释、SELECT '你好' 这类字面量,是在 CREATE PROCEDURE 语句执行时被 MySQL 一次性解析并存入 mysql.proc 表的。如果此时会话的 character_set_client 是 latin1 或 gbk,那两个汉字字节就会被错误解码,写进系统表就已损坏——后续怎么改配置都救不回来。
所以无论你是否改过 my.cnf,只要建过程前没显式设置,就极大概率出问题。
- 每次新建或重定义过程前,先运行:
SET NAMES utf8mb4; - 验证三值是否对齐:
SHOW VARIABLES LIKE 'character\_set%';,重点确认character_set_client、character_set_connection、character_set_results全是utf8mb4 - 批量执行 SQL 文件时,把
SET NAMES utf8mb4;放在第一行,不要依赖客户端默认行为
my.cnf 必须覆盖 [client]、[mysql]、[mysqld] 三段
只在 [mysqld] 段写 character-set-server=utf8mb4 是无效的。MySQL 启动后,服务端默认值不影响客户端怎么连进来。很多乱码问题根源就在 [client] 和 [mysql] 段缺失或写错。
正确配置示例(Linux 下通常为 /etc/my.cnf):
[client] default-character-set = utf8mb4 <p>[mysql] default-character-set = utf8mb4</p><p>[mysqld] character-set-server = utf8mb4 collation-server = utf8mb4_unicode_ci
改完必须重启服务:systemctl restart mysqld;reload 不生效。
连接字符串里也要声明 charset=utf8mb4
即使服务器和本地配置都对了,应用层(如 Python 的 pymysql、Java 的 JDBC、C# 的 MySqlConnector)仍可能用默认 latin1 发起握手。这时你写的 CALL my_proc() 请求,MySQL 会按错误字符集去解析返回结果,导致字段值变问号。
- Python
pymysql:连接时加charset='utf8mb4'参数 - JDBC:
jdbc:mysql://host:3306/db?useUnicode=true&characterEncoding=utf8mb4 - C#:
server=localhost;database=test;charset=utf8mb4; - 命令行客户端:
mysql --default-character-set=utf8mb4 -u root -p
别在存储过程内部用 SET character_set_results 临时切换
过程体里写 SET character_set_results = latin1; 这类语句,会导致后续 SELECT 返回结果被强制转成 latin1,再经客户端按 utf8mb4 解析,必然乱码。更隐蔽的是它会影响整个会话,污染后续其他查询。
真正需要控制输出编码的地方,应该靠外部连接参数统一管理,而不是在过程里做运行时切换。
最易被忽略的一点:存储过程创建成功 ≠ 中文没损坏。得实际 CALL 一次,再查返回内容或看 SHOW CREATE PROCEDURE 里的注释是否还是原样——很多问题要到这一步才暴露。


















