“access denied”是因user表无匹配的'user'@'host'记录,而非密码错误;改host为%常无效,因localhost、ipv6、域名不匹配,且需flush privileges生效;grant创建用户更可靠,并注意安全组放行。

“Access denied”不是密码错了,而是 MySQL 根本没让你进校验密码那关——user 表里压根没有匹配你连接时用的 'user'@'host' 这条记录。
为什么改 Host 字段为 % 常常不管用
直接 UPDATE mysql.user SET Host = '%' 看似一步到位,但实际踩坑极多:
-
'user'@'localhost'和'user'@'%'是两条完全独立的账号,改其中一条不影响另一条; - MySQL 8.0+ 对
'%'的匹配有隐含限制:不匹配localhost(走 socket)、不匹配 IPv6 地址(如::1),也不匹配带域名的 host(如%.example.com); - 如果原记录是
'user'@'127.0.0.1',改成'%'后仍可能因 DNS 解析或客户端强制解析成localhost而失效; - 修改表后不执行
FLUSH PRIVILEGES,权限不会加载,查SHOW GRANTS FOR 'user'@'%'会返回空。
GRANT 创建用户比手改 user 表更可靠
用 GRANT 语句创建远程用户,MySQL 会自动处理插件、认证方式和权限存储格式:
对设计或页面进行 WCAG 2.1 AA 无障碍审计。触发关键词:“audit accessibility”、 “check a11y”、 “is this accessible?” 或在审查设计时使用。
- 优先用
CREATE USER 'dev'@'%' IDENTIFIED BY 'pwd'+GRANT SELECT ON mydb.* TO 'dev'@'%',而不是INSERT INTO mysql.user; - 若需兼容老客户端(如旧版 Navicat 或 PHP mysqli),加一句
ALTER USER 'dev'@'%' IDENTIFIED WITH mysql_native_password BY 'pwd'; - 避免对已有
'root'@'localhost'直接改Host——它专用于本地 socket 连接,强行改成%可能导致本地命令行mysql -u root失败。
检查 Host 匹配是否真生效
别猜,查日志、看连接来源、验证实际匹配路径:
- 连不上时立刻查错误日志:
tail -n 20 /var/log/mysql/error.log,里面常有 “Access denied for user 'dev'@'192.168.1.100'” 这样的精确提示; - 用
SELECT User, Host FROM mysql.user WHERE User = 'dev'确认结果里真有'dev'@'%'这一行(注意单引号、大小写、空格); - 从客户端连时明确指定 host:
mysql -h 192.168.1.100 -u dev -p,不要依赖默认 host; - 云服务器上,
'%' 不等于“所有 IP”——安全组/ACL 必须放行对应端口(3306)和源 IP 段,否则连接根本发不到 MySQL。
真正容易被忽略的是:MySQL 的 Host 字段是**精确字符串匹配**,不是通配符模糊搜索。改完 % 却还连不上,大概率是因为你连的是 'dev'@'192.168.1.100',而表里只有 'dev'@'%' ——看起来该匹配,但中间卡了 DNS 反解、IPv6 fallback 或客户端预设 host。先查日志里拒绝时写的到底是哪个 'user'@'host',再动手。










