mysql中user()返回客户端声明的用户和主机,current_user()返回服务器实际认证的账号;二者不一致时,权限以current_user()为准,show grants也仅显示其对应权限。

SELECT USER() 和 SELECT CURRENT_USER() 必须并排对比
只查 USER() 会误以为自己是以某个具体 IP 连入的账号在运行,但权限实际由 CURRENT_USER() 决定。二者不一致是常态,不是异常。
-
USER()显示你“填了什么”:比如'app@10.20.0.42',但它可能根本没在mysql.user表里存在 -
CURRENT_USER()显示 MySQL “认了谁”:比如'app'@'%',说明匹配到了这条记录,所有权限都按它来算 - 执行
SELECT USER(), CURRENT_USER();一行出结果,立刻看出是否发生 host 匹配降级(如从app@192.168.1.5降到app@'%')
查 mysql.user 表时必须用 ORDER BY 模拟匹配顺序
MySQL 不是随机选账号,而是按固定优先级扫描 mysql.user 表——越精确的 Host 值越靠前,User 字段只在 Host 相同时才参与排序。
- 真实匹配顺序是:
SELECT User, Host FROM mysql.user ORDER BY Host DESC, User DESC; - 注意:这里的
DESC是关键。因为'192.168.1.5'>'192.168.%'>'%'(字符串比较),所以更具体的 host 排前面 - 如果你看到
CURRENT_USER()返回'app'@'%',但表里明明有'app'@'192.168.1.%',那说明那条记录被更靠前的其他用户(比如空User或更高优先级Host)挡住了
SHOW GRANTS 默认查的是 CURRENT_USER() 的权限
执行 SHOW GRANTS; 时不加 FOR 子句,它查的永远是 CURRENT_USER() 对应的权限记录,不是你连接时声明的那个。
- 如果
CURRENT_USER()是'app'@'%',SHOW GRANTS;就等价于SHOW GRANTS FOR 'app'@'%'; - 想确认某条具体记录是否生效?先用
CURRENT_USER()拿到准确的'user'@'host',再显式执行SHOW GRANTS FOR 'user'@'host'; - 普通用户执行
SHOW PROCESSLIST;时,输出里的USER列显示的也是CURRENT_USER(),不是USER()——这点容易误导排查
HOST 匹配失败时会静默降级到 '%',但不会报错
这是最隐蔽的坑:DNS 解析失败、IPv6 地址格式不匹配、Unix socket 被识别为 localhost 等情况,都会导致 MySQL 找不到精确匹配项,直接跳到 'user'@'%'。
- 现象:你用
mysql -h 2001:db8::1 -u app连,USER()显示'app'@'2001:db8::1',但CURRENT_USER()是'app'@'%' - 验证方式:查
SELECT User, Host FROM mysql.user WHERE User = 'app';,看有没有 IPv6 格式的Host条目 - 特别注意 Unix socket:即使你指定
-h 127.0.0.1,只要没加--protocol=tcp,MySQL 仍走 socket,CURRENT_USER()很可能是'app'@'localhost'
ORDER BY Host DESC, User DESC 的结果,光看 mysql.user 表数据本身,根本没法判断哪条被选中。











