根本原因是客户端、连接层、表结构三者字符集不一致,Navicat默认用latin1或utf8(非utf8mb4)建连,而MariaDB实际用utf8mb4存中文;必须显式声明SET NAMES utf8mb4或配置连接使用utf8mb4。
Navicat 连 MariaDB 时中文显示为问号或方块
根本原因是客户端、连接层、表结构三者字符集不一致,常见于 navicat 默认用 latin1 或 utf8(非 utf8mb4)建连,而 mariadb 实际用 utf8mb4 存中文。不是“数据库没设对”,而是“连的时候没说清楚自己要什么”。
- 检查当前连接实际使用的字符集:
SELECT @@character_set_client, @@character_set_connection, @@character_set_results; - Navicat 新建连接时,在「高级」页勾选「使用 MySQL 字符集」并手动设为
utf8mb4(不是utf8) - 如果已建连接,右键→「编辑连接」→「高级」→「初始化命令」里加一句:
SET NAMES utf8mb4; - 避免只改
my.cnf却不重连——Navicat 不会自动读取服务端配置,必须显式声明
MariaDB 服务端配置 utf8mb4 但 Navicat 仍乱码
服务端配得再全,Navicat 连接时若没传递正确编码,照样走默认 fallback(通常是 latin1)。关键不在“有没有”,而在“连的时候认不认”。
-
my.cnf中需同时设置四类参数(缺一不可):character-set-server = utf8mb4、collation-server = utf8mb4_unicode_ci、init_connect = 'SET NAMES utf8mb4'、skip-character-set-client-handshake(慎用,仅当所有客户端可信时) -
init_connect对 root 用户无效,所以用 root 连时仍需在 Navicat 里手动加SET NAMES utf8mb4 - 修改
my.cnf后必须重启mariadb服务,systemctl restart mariadb,光 reload 不生效
表和字段已经是 utf8mb4,但 Navicat 插入中文仍变 ?
表结构对不代表连接对。插入失败时查 SHOW WARNINGS;,大概率看到 Warning | 1366 | Incorrect string value —— 这是字符被截断或替换的明确信号,源头一定是连接层编码不匹配。
- 确认当前 session 编码:
SHOW VARIABLES LIKE 'character\_set%';,重点看character_set_client和character_set_results是否为utf8mb4 - Navicat 执行查询前,先手动运行:
SET NAMES utf8mb4;,再执行 INSERT,观察是否还报错 - 如果用 Navicat 的「数据传输」或「结构同步」功能,务必在向导中勾选「保持字符集」,否则它可能按自身默认编码重建表
- 旧表即使
ALTER TABLE ... CONVERT TO CHARACTER SET utf8mb4,也不影响已有连接的编码行为
为什么非得用 utf8mb4 而不是 utf8
MariaDB 的 utf8 是阉割版,最多存 3 字节字符(如 emoji、部分生僻汉字、繁体异体字),真正完整的 UTF-8 是 utf8mb4。用 utf8 看似能存中文,但遇到 ?、??、? 就直接报错或丢数据。
-
utf8在 MariaDB 中等价于utf8mb3,官方已标记为 deprecated - Navicat 的字符集下拉菜单里写的 “UTF-8” 实际对应服务端的
utf8mb4,不是utf8—— 别被名字骗了 - 应用层(PHP/Python)也要同步用
utf8mb4,比如 PDO DSN 加;charset=utf8mb4,否则只是半程加密
最常被忽略的是:Navicat 每个连接是独立的,改完全局配置不等于所有已有连接自动更新。连上之后第一件事,就是确认 character_set_client 是不是你想要的值。


















