mysql如何处理Access denied拒绝访问_mysql权限与密码重置

3次阅读

access denied 错误拒绝的是连接请求中指定的 user@host 身份,因该身份未被授权登录;user@host 是完整认证单元,root@localhost 与 root@127.0.0.1 视为不同账户,权限可能不一致。

mysql如何处理Access denied拒绝访问_mysql权限与密码重置

Access denied for user 错误到底在拒绝谁

这个错误不是 mysql 在“随机发脾气”,而是明确告诉你:当前连接尝试的身份(用户名 + 主机名 + 密码)没被授权登录。注意,user@host 是一个完整身份,root@localhostroot@127.0.0.1 在 MySQL 里是两个不同账户,权限可能完全不同。

常见错误现象:

  • mysql -u root -p 能登本地,但用 mysql -h 127.0.0.1 -u root -p 就报错
  • 新建用户后立刻用 navicat 连,提示 Access denied,但命令行用相同参数却能连
  • 修改了 root 密码,服务重启后 PHP 连不上,但命令行能连

关键判断点:

  • 检查你实际连接时的 host 是什么(select USER(), CURRENT_USER();
  • CURRENT_USER() 返回的是 MySQL 认证通过的身份,它才是权限系统真正检查的对象

跳过密码验证重置 root 密码的实操步骤

仅适用于你能直接访问 MySQL 服务器操作系统且有 sudo 权限的场景。别在生产环境盲操作,尤其别在没备份的情况下停库。

操作前确认:

  • MySQL 版本 ≥ 5.7.6(ALTER USER 语法才稳定支持)
  • mysqld 正在运行,且你知道它的配置文件路径(通常是 /etc/my.cnf/etc/mysql/mysql.conf.d/mysqld.cnf

步骤:

  • 停止 MySQL 服务:sudo systemctl stop mysql
  • 启动 mysqld 并跳过权限表:sudo mysqld --skip-grant-tables --skip-networking &
  • 直接登录(此时不校验密码):mysql -u root
  • 执行重置(MySQL 5.7+ 必须用 ALTER USERUPDATE mysql.user 不再生效):
    FLUSH PRIVILEGES; ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY '你的新密码';
  • 退出后正常重启服务:sudo systemctl start mysql

⚠️ 容易踩的坑:

  • 忘记加 --skip-networking,导致远程未授权连接可趁虚而入
  • 重置后没执行 FLUSH PRIVILEGES;,新密码不生效
  • SET PASSWORD 或旧式 UPDATE 语句,在 8.0+ 会报错或静默失败

为什么 grant all privileges 之后还是 Access denied

GRANT 不等于“立刻生效”,也不等于“覆盖所有 host”。最常漏掉的三个条件:

  • 权限只对指定的 host 生效,比如 GRANT ALL ON <em>.</em> TO 'app'@'192.168.1.%'192.168.1.100 有效,但对 localhost 无效
  • 没有 FLUSH PRIVILEGES;(虽然多数情况自动刷新,但某些版本或特殊配置下必须显式执行)
  • 用户认证插件不匹配:MySQL 8.0 默认用 caching_sha2_password,老客户端(如 MySQL 5.7 客户端、部分 PHP pdo 驱动)不支持,需显式指定插件:
    ALTER USER 'app'@'%' IDENTIFIED WITH mysql_native_password BY 'pwd';

其他典型问题:

  • 创建用户时用了单引号把 IP 写成字符串'192.168.1.100' → 应该不加引号或用通配符
  • 忘记授权 mysql 系统库以外的库,而应用连接时指定了 -D mysql 或默认库
  • 使用了 DNS 解析,host 实际被解析为域名,但权限只给了 IP —— 可关掉 skip-name-resolve 或直接授予权限给域名

忘记密码又不能停库?试试 init-file 方式

适用于无法中断服务、但能写入 MySQL 配置目录的场景(比如容器内挂载配置、云数据库允许自定义启动参数)。

原理:让 mysqld 启动时自动执行一段 SQL,修改密码后再删掉文件,避免长期暴露风险。

操作要点:

  • 创建临时 SQL 文件,例如 /tmp/reset.sql,内容为:
    ALTER USER 'root'@'localhost' IDENTIFIED BY '新密码';
  • 在配置文件 [mysqld] 段加入:init-file = /tmp/reset.sql
  • 重启 MySQL(此时会执行该 SQL)
  • 立刻删除 /tmp/reset.sql 并从配置中移除 init-file 行,防止下次重启又被覆盖

⚠️ 注意:

  • 文件路径必须是 mysqld 进程有读取权限的路径(非 root 用户启动时,/tmp 可能不可读)
  • 如果配置错误导致启动失败,MySQL 会卡住,需手动清理并检查错误日志:/var/log/mysql/Error.log
  • 该方式在 MySQL 8.0.14+ 支持更安全的 --init-command,但兼容性不如 init-file

权限系统真正麻烦的地方不在语法,而在 host 匹配逻辑和认证插件的隐式切换——这两点不亲手查一遍 SELECT Host,User,plugin FROM mysql.user;,光看文档永远容易漏掉。

text=ZqhQzanResources