mysqld 启动时必须同时使用 --skip-grant-tables 和 --skip-networking 才安全;仅用前者会导致权限表裸奔,改密码后仍无法登录;mysql 5.7+ 需更新 authentication_string 字段并执行 flush privileges;8.0+ 还需确保 root 的 plugin 为 mysql_native_password 或 caching_sha2_password。

mysqld 启动时加 --skip-grant-tables 能绕过密码验证,但必须配合 --skip-networking
不加 --skip-networking 的话,MySQL 仍会监听端口,任何本地用户都可能连上并直接修改权限表——这不是重置密码,是裸奔。实际操作中,--skip-grant-tables 单独启动后,你大概率遇到 Access denied for user 'root'@'localhost' 或改完密码仍无法登录,问题就出在这里。
正确做法是:停掉 MySQL,用两个参数一起启动:
mysqld --skip-grant-tables --skip-networking &
注意:& 是后台运行,别漏掉;如果用 systemd 管理,得先 systemctl stop mysql,再手动起进程,别试图改 service 文件临时加参数——容易因配置加载顺序失效。
登录后必须用 UPDATE mysql.user 改 authentication_string,不是 password
MySQL 5.7.6+ 彻底移除了 password 字段,改用 authentication_string 存哈希值。用老教程里的 SET PASSWORD 或 UPDATE ... SET password=... 会静默失败,或者写进错字段,导致 root 账户变“空密码但无法登录”的诡异状态。
执行以下语句(注意替换为你想设的密码):
USE mysql;<br>UPDATE user SET authentication_string = PASSWORD('你的新密码') WHERE User = 'root';<br>FLUSH PRIVILEGES;
说明:
-
PASSWORD()函数在 8.0+ 已废弃,但 5.7 仍可用;如用 MySQL 8.0,改用ALTER USER 'root'@'localhost' IDENTIFIED BY '新密码'; - 必须执行
FLUSH PRIVILEGES;,否则内存权限缓存不更新,改了白改 - 别忘了
WHERE User = 'root',漏条件可能误改其他账户
重启服务前务必杀掉 --skip-grant-tables 进程,否则权限系统始终失效
很多人改完密码就直接 systemctl start mysql,结果发现服务起不来、或起来后还是免密可登录——因为之前手工起的 mysqld 进程还在跑,占着端口,systemd 启动的是另一个实例,但你连的其实是那个跳过权限检查的老进程。
安全收尾三步:
- 查进程:
ps aux | grep mysqld,找到带--skip-grant-tables的那一行 - 杀掉它:
kill -9 [PID](别只 kill 名字,容易杀错) - 再用常规方式启动:
systemctl start mysql或service mysql start
验证是否生效:用新密码登录 mysql -u root -p,成功即表示回归正常权限模型。
8.0+ 用户注意 plugin 字段必须是 caching_sha2_password 或 mysql_native_password
MySQL 8.0 默认用 caching_sha2_password 插件,但有些客户端(尤其是旧版 PHP、Navicat 或脚本里没指定插件)只认 mysql_native_password。即使密码改对了,也会报 Client does not support authentication protocol。
登录后检查并修正:
SELECT Host, User, plugin FROM mysql.user WHERE User = 'root';
如果 plugin 是空或异常值,强制设回兼容插件:
ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY '你的新密码';<br>FLUSH PRIVILEGES;
这个点常被忽略,尤其当你在 Docker 容器或自动化脚本里重置密码时,客户端环境不可控,不显式指定插件,后续连接就是一堵墙。











