‘user’@'%' 不等于 ‘user’@'localhost',因为MySQL对localhost采用Unix socket特殊路径且精确匹配host字段,%仅匹配TCP/IP连接(含127.0.0.1),不覆盖localhost;同一用户名在不同host下是独立账号,权限、密码、认证插件均需分别配置。
MySQL 的 user 表里,host 字段是精确匹配的。'test'@'%' 允许从任意 IPv4/IPv6 地址(包括 127.0.0.1)连接,但不包含 localhost——因为 MySQL 对 localhost 有特殊处理逻辑,它会优先尝试 Unix socket 连接,且只认 'test'@'localhost' 这条记录。
mysql -utest -hlocalhost -p 查的是 host = 'localhost' 的行,不是 '%'
mysql -utest -h127.0.0.1 -p 才走 TCP,匹配 'test'@'%'
host 下是完全独立的账号,密码、权限、锁定状态都可能不同这个报错本身已经指明问题根源:MySQL 找到了 'xxx'@'localhost' 这条记录,但校验失败。常见原因不是没授权,而是:
'xxx'@'%' 设了密码,'xxx'@'localhost' 还是空密码)account_locked = 'Y'(MySQL 5.7+ 默认新用户不锁,但手动锁过就需解锁)plugin 字段是 auth_socket 或 unix_socket(Ubuntu 默认安装常用,只认系统用户,不认密码)查证命令:SELECT user, host, plugin, account_locked FROM mysql.user WHERE user = 'xxx';
最稳妥的做法是显式创建两条记录,而不是依赖通配符覆盖:
GRANT ALL ON *.* TO 'xxx'@'%' IDENTIFIED BY 'pwd';
GRANT ALL ON *.* TO 'xxx'@'localhost' IDENTIFIED BY 'pwd';
FLUSH PRIVILEGES;,否则变更不生效注意:如果已存在 'xxx'@'localhost' 记录,GRANT 不会覆盖密码,得先 DROP USER 'xxx'@'localhost'; 或用 ALTER USER 显式改密。
启用 IPv6 后,部分系统(如某些 Linux 发行版)会让 localhost 解析为 ::1 而非 127.0.0.1,这时 'xxx'@'localhost' 仍有效,但 'xxx'@'127.0.0.1' 就不匹配了。真正要补的是:
GRANT ... TO 'xxx'@'::1' IDENTIFIED BY 'pwd';'xxx'@'127.0.0.1' 和 'xxx'@'::1' 替代 'xxx'@'localhost',避免 socket 路径干扰关键点在于:localhost 的语义在 MySQL 内部是固定的(强制走 socket),和 DNS 解析无关;但如果你在客户端显式写 -hlocalhost,而系统 hosts 把它映射成 ::1,MySQL 客户端可能 fallback 到 TCP 并尝试连 ::1,此时就需要对应授权。