还原sql文件后中文变问号的根源是mysql连接层字符集未对齐,必须确保character_set_client、character_set_connection、character_set_results三者均为utf8mb4,且表结构也使用utf8mb4。
还原 sql 文件后中文变问号,不是文件没保存好,而是连接层字符集没对齐——navicat 导入时完全依赖当前连接的 character_set_client 和 character_set_connection,这两个值错一个,中文就丢一半。
执行 SHOW VARIABLES LIKE 'character_set%' 看清真实状态
别信 Navicat 界面右下角显示的“UTF-8”,它只是编辑器编码提示。真正决定还原行为的是 MySQL 服务端返回的变量值:
-
character_set_client:MySQL 用这个编码去解你发来的 SQL 字节流 -
character_set_connection:SQL 解析过程中临时转换用的中间编码 -
character_set_results:查询结果返回给 Navicat 时按什么编码打包
三者必须全是 utf8mb4,缺一不可。如果其中一个是 latin1 或 gbk,哪怕 SQL 文件本身是 UTF-8 无 BOM,导入时也会双次错乱。
Navicat 连接高级设置里必须填 SET NAMES utf8mb4
光在「默认字符集」选 UTF-8 不够,那只是影响编辑器打开文件的解码方式;还原动作走的是连接通道,必须让每次新建会话都强制初始化:
- 右键连接 → 编辑连接 → 高级 → 勾选「初始化命令」→ 输入:
SET NAMES utf8mb4; - 注意不是
utf8:MySQL 的utf8是阉割版,不支持 emoji 和部分生僻汉字,utf8mb4才是完整 UTF-8 - 不要写成
SET NAMES utf8mb4 COLLATE utf8mb4_unicode_ci:MySQL 不认这种写法,会报语法错误
SQL 文件头加 /*!40101 SET NAMES utf8mb4 */ 更保险
Navicat 的「运行 SQL 文件」功能不校验文件内容,但 MySQL 服务端会执行带 ! 的条件注释。加上这句能覆盖掉文件里可能残留的旧 SET NAMES latin1:
- 用 VS Code 或 Notepad++ 打开 SQL 文件,在第一行插入:
/*!40101 SET NAMES utf8mb4 */ - 保存为「UTF-8 无 BOM」格式:Windows 记事本默认带 BOM,Navicat 读取时容易误判为 ANSI
- 如果文件里已有
SET NAMES utf8,必须手动替换成utf8mb4,否则它会覆盖连接层设置
还原前确认目标库表结构也用 utf8mb4
连接层设对了,不代表数据能存进去。如果表字段定义仍是 CHARACTER SET latin1,MySQL 会在入库时强行转码,导致 Incorrect string value 错误或静默截断:
- 查表实际字符集:
SHOW CREATE TABLE `your_table`;,看字段定义末尾有没有CHARACTER SET utf8mb4 - 已有表修复:
ALTER TABLE `your_table` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; - 注意:大表执行会锁表,生产环境建议在低峰期操作,或用 pt-online-schema-change
最常被忽略的一点:Navicat 的「数据传输」功能比「运行 SQL 文件」更可靠——它会自动探测源库和目标库能力,跳过不兼容的排序规则(比如把 utf8mb4_0900_ai_ci 自动降级为 utf8mb4_unicode_ci),跨版本还原时优先用它。











