select user()和current_user()不一致说明host字段未精确匹配,mysql退而使用通配符或强制识别为localhost,表明权限未作用于声称的账号。

SELECT USER() 和 CURRENT_USER() 返回不一致说明什么
这几乎就是主机名解析干扰权限匹配的铁证。USER() 显示你“声称”的连接来源(比如 app@'web01.example.com'),而 CURRENT_USER() 才是 MySQL 实际查 mysql.user 表时匹配到的账户(比如 app@'%' 或 app@'10.0.2.5')。两者不同,说明 Host 字段没对上——不是权限没给,是根本没走到那个账号。
常见表现:
-
USER()是app@'DESKTOP-ABC123',CURRENT_USER()却是app@'%':说明 DNS 解析失败,退化到通配符匹配 -
USER()是app@'127.0.0.1',CURRENT_USER()却是app@'localhost':说明你用 TCP 连 127.0.0.1,但 MySQL 认为你走的是 socket(Linux 下常见),因为skip-name-resolve没开或没生效
错误日志里出现 “unauthenticated user” 就别折腾密码了
只要 mysqld 错误日志里反复刷出 unauthenticated user,基本可以排除密码错、用户不存在、防火墙拦截这些常规问题。这是服务端在调用 gethostbyaddr() 反解客户端 IP 失败或超时的明确信号——线程卡在 login 状态,连认证环节都没进。
验证方式:
- 执行
SELECT @@skip_name_resolve;,返回OFF(即 0)就确认未关闭解析 - 运行
SHOW PROCESSLIST;,如果大量连接的Host列显示 IP 地址(如10.0.2.5:52183)且Command是Connect,说明还在尝试反查 - 临时停 DNS:执行
sudo systemctl stop systemd-resolved,再试mysql -h 127.0.0.1 -u app -p;秒进就坐实是 DNS 阻塞
skip-name-resolve=ON 必须写对位置、重启才生效
这个参数只对服务端起作用,写在 [client]、[mysql] 或配置文件开头一律无效。它必须出现在 [mysqld] 段内,且要真正重启服务,systemctl reload mysql 不会加载新值。
容易踩的坑:
- Ubuntu/Debian 用户常被
!includedir /etc/mysql/conf.d/覆盖主配置,先运行mysqld --verbose --help | grep "Default options"确认最终加载路径 - Windows 用户把配置写进了
my.ini的全局区,而不是[mysqld]段下 - 开了
skip-name-resolve后,'root'@'localhost' 和'root'@'127.0.0.1' 彻底变成两个独立账号,原来靠域名授权的账号全部失效
生效后必须验证:mysql -e "SHOW VARIABLES LIKE 'skip_name_resolve';" 输出 ON 才算成功。
开了 skip-name-resolve 后权限全挂了?这不是 bug,是设计
启用后,MySQL 彻底跳过所有 DNS 解析,mysql.user 表里的 Host 字段只能做字面匹配:IP 地址、%、localhost(注意:仅当用 socket 连接时才匹配这个字符串)、::1。它不再识别 web01.example.com、DESKTOP-ABC123 这类主机名,也不会把 127.0.0.1 自动转成 localhost。
所以必须立刻补救:
- 把所有非 IP /
%的Host值批量替换掉:比如UPDATE mysql.user SET Host = '10.0.2.5' WHERE User = 'app' AND Host = 'web01.example.com'; - 或者统一改成网段通配:
UPDATE mysql.user SET Host = '10.0.2.%' WHERE Host = 'web01.example.com'; - 执行
FLUSH PRIVILEGES;(MySQL 8.0+ 通常自动,但保险起见仍建议执行)
最易忽略的一点:Linux 下 localhost 默认走 Unix socket,而 127.0.0.1 走 TCP —— 这俩连接方式触发的 CURRENT_USER() 完全不同,授权必须分开处理。











