干运维这些年,被 root 密码卡住的“名场面”我见得太多了。新同事交接时丢下一句“密码在群里”,结果翻遍聊天记录全是过期的旧文件;老板半夜打电话说服务器登不上了;更常见的是数据库连接报 1045,Access denied for user 'root'@'localhost'——你说这个 root 到底是改了还是没改?
这篇文章就把 root 密码那点事一次讲透:从系统 root 密码的正常修改、忘记密码后的应急重置,到 MySQL/MariaDB 数据库 root 账号密码的设置与找回,再到改完密码之后必须同步做好的运维动作。不管你是刚接触 Linux 的小白,还是已经被 root 密码坑过几次的运维,都能从这里找到可以直接抄的作业。
1. 先摸清 root 的底细:它为什么是运维的命门
1.1 UID=0 背后的权限模型
在 Linux 里,root 不是一个“职位”,它是一个真实存在的账号,UID 固定为 0。你可以在/etc/passwd里看到这一行:
root:x:0:0:root:/root:/bin/bash那个x表示密码真正存放的位置在/etc/shadow文件里,普通用户看不到 hash。整个系统的权限判断,内核几乎不看用户名,只看 UID 是不是 0。只要 UID 是 0,就意味着它可以绕过几乎所有的权限校验:任意文件读写、任意进程信号、绑定 1024 以下端口、加载内核模块、修改网络配置和防火墙规则,统统不在话下。
用生活里的话打比方,root 就是整栋大厦的总钥匙。总钥匙能开任何一间房,但一旦丢了一把,你不可能为了它把所有门锁都换掉,只能想方设法找回或者重新配。更麻烦的是,root 账号一旦被别人掌握,他不仅能看到所有租户的文件,还能在不留下明显痕迹的情况下安装后门、改日志、清痕迹。这就是为什么 root 密码管理永远是服务器安全的第一道门。
很多人有个误解:觉得自己电脑上的 root 密码无所谓。但一旦这台机器上了生产环境,或者开放了 SSH 端口,root 密码泄露基本等于服务器拱手让人。所以搞清楚 root 的权限模型,是后面所有操作的前提。
1.2 密码丢失的几种典型场景
我接触过的 root 密码丢失,来来回回逃不出这几种情况:
- 人员交接不完整:老员工离职,服务器密码只在他脑子里,交接文档里写着“见 XX 文档”,结果那个文档早就删了。
- 密码策略强制过期:公司安全策略要求 90 天改一次密码,某台设备没人登录,等你想起来时密码已经过期,SSH 直接拒绝登录。
- 误操作:批量脚本改密码时写错了目标主机,或者有人手滑把
/etc/shadow的权限改了、内容清空了。 - 僵尸服务器:测试环境、临时业务机,跑了大半年没人碰,真正要用的时候谁也不记得密码。
- 云服务器场景:部分云平台默认只开放密钥登录,密码从来不设置,等密钥丢失后一脸懵。
这些场景的共同点是:平时你觉得 root 密码“反正又用不到”,等到真正需要的时候才意识到,它就是那一把唯一能开门的钥匙。所以建议每台机器上线时第一件事就是设置好 root 密码,并把密码放进团队共用的密码管理平台,而不是靠某个人脑子记。
1.3 系统 root 与数据库 root 别搞混
这是新手最容易踩的坑:系统 root 是 Linux 操作系统的超级管理员,数据库 root 是 MySQL/MariaDB 里的超级管理员,两者之间没有任何等价关系。你改了服务器系统的 root 密码,MySQL 的 root 密码一点不变;反过来,你在 MySQL 里ALTER USER也不会影响 SSH 登录。
很多人在排错的时候,遇到ERROR 1045 (28000): Access denied for user 'root'@'localhost',第一反应是去改系统 root 密码,改完了发现完全没用。原因很简单:mysqld 是以mysql系统用户身份运行的,它只认自己权限表里的账号信息。这个混淆如果不在最开始讲清楚,后面所有操作都会乱。
所以这篇文章的节奏是:先把系统 root 的修改和重置讲明白,再单独讲数据库 root。两条线分开走,问题才能拆得干净。
2. 密码还记得:改 root 密码的标准操作与权限边界
2.1 passwd 命令的正确打开方式
如果现在还能用 root 登录,修改密码就是一条命令的事:
passwd root系统会提示输入两次新密码,然后写入/etc/shadow。如果你已经是用 root 身份登录,直接执行passwd不带参数也是修改当前用户(就是 root)。
实际工作里,很多时候需要在脚本里非交互式改密码,可以用这种方式:
echo 'NewPass_123' | passwd --stdin root注意--stdin是 RHEL/CentOS 系的参数,Debian/Ubuntu 系默认不支持。跨发行版更通用的做法是用chpasswd:
echo "root:NewPass_123" | chpasswd修改密码后,旧密码立刻失效,所有正在使用旧密码的登录会话不会马上掉线(SSH 已经认证过的连接继续有效),但新登录必须使用新密码。密码强度校验由 PAM 的pam_pwquality模块控制,如果你设置的密码太弱,比如纯数字或者常见单词,系统会提示BAD PASSWORD并拒绝。虽然 root 在部分配置下可以强行绕过弱密码检查,但生产环境强烈不建议这么干。
这里还要多说一句:密码里的特殊字符尽量避免$、反引号、单引号这类在 shell 里容易被解释的字符,尤其是在双引号字符串里拼接命令时容易踩坑。建议用openssl rand -base64 18这类工具生成强密码,然后复制粘贴。
2.2 sudo、su 与 passwd 的权限关系
修改 root 密码的权限边界,很多人没有仔细想过。这里梳理清楚:
su -切换到 root,需要输入 root 密码。sudo passwd root,不需要 root 密码,只需要当前用户有 sudo 权限,输入当前用户的密码即可。- 普通用户如果被加入了
wheel组(RHEL 系)或sudo组(Debian 系),就拥有执行sudo的资格。
这意味着一个现实:能 sudo 的用户,约等于能修改 root 密码。因为sudo passwd root不需要旧密码。所以在做权限划分时,不要随便把不信任的人加进 sudo 组。我见过不少公司,运维团队每人都有 sudo 权限,root 密码本身反而没什么价值,真正的安全防线变成了 sudo 用户自身的密码强度和审计。
另外,很多软件安装包(比如部分 GUI 安装器)会检测到 root 用户直接拒绝运行,报错信息类似cannot install as root user !。这不是 bug,是安装器出于安全考虑,不想让你在超级用户权限下跑未知的安装逻辑。正确处理方式是切回普通用户,用sudo执行安装命令,而不是傻傻地切到 root 硬装。
还有一个常见操作叫“切换 root”。我的建议是,生产环境尽量少用su -切到 root 交互式操作,因为你输入root密码本身就可能被键盘记录或者历史命令记录。更可审计的做法是每条命令前面加sudo,让 sudo 的审计日志留下记录。
2.3 改完密码后必须同步做的四件事
改密码本身十秒钟,改完之后的连锁反应才是重头戏。我在生产环境操作完一次密码修改后,一定会确认这几件事:
新开一个 SSH 会话验证登录。千万不要在唯一的会话里改完密码就退出,万一新密码没生效或者密码策略有特殊要求,你可能就把自己锁在门外了。正确做法是改完之后,另开一个窗口测试登录,确认没问题再关闭旧会话。
更新所有依赖 root 密码的周边配置。cron 脚本、备份任务、Ansible/Salt 等配置管理工具里的变量、监控系统采集账号,全部要跟着改。这里我吃过一次亏:改了服务器 root 密码,但备份脚本里还写着旧密码,结果这个备份偷偷失败了大半个月才被发现。
通知团队相关人员,并更新密码管理平台。如果密码只改在你的脑子里,等于没改。建议第一时间把新密码录入团队共用的密码管理平台(比如 KeePass、Bitwarden 或专业的运维凭据系统),并且删除聊天软件里的明文传输记录。
检查连带服务。如果你这台服务器上有 Docker 容器映射了系统账号、有服务用 root 身份对外提供 FTP 这类登录入口,也要确认新密码是否影响这些服务的凭据验证。
这个清单看起来琐碎,但在生产环境漏掉哪一步都可能造成事故。我个人强烈建议把“改完密码后的检查项”写成固定 checklist,每次操作都走一遍。
3. 密码忘了也能救:三套 root 密码重置方案实测
3.1 单用户模式:CentOS 7/RHEL 7 的 rd.break 流程
如果系统 root 密码忘了,只要你有物理访问权限(或者云服务器通过 VNC 控制台访问),重置并不难。这里以 CentOS 7/RHEL 7 最常用的rd.break方案为例。
具体步骤:
- 重启服务器,在 GRUB 菜单界面选中当前内核,按
e进入编辑模式。 - 找到以
linux16(或linux)开头的那一行,定位到行尾,在后面加上一个参数:rd.break。 - 按
Ctrl+X启动。系统会进入 initramfs 的紧急 shell,根目录此时是只读模式,且挂载在/sysroot下。 - 输入以下命令,把根目录重新挂载为可写:
mount -o remount,rw /sysroot- 切换到真实系统根目录:
chroot /sysroot- 重置密码:
passwd root- 如果系统启用了 SELinux,必须执行这一步:
touch /.autorelabel- 连续输入
exit退出 chroot 和 shell,然后reboot重启。
为什么这里要用touch /.autorelabel?因为直接跳过 SELinux 上下文标记可能会导致重启后系统文件的安全上下文不正确,严重时连登录都进不了。加了这行,系统在下次启动时会自动重建 SELinux 标签,代价是第一次启动会比较慢,耐心等就行。
3.2 Ubuntu/Debian 的 GRUB 重置方案
Ubuntu 系的思路类似,但进入方式略有不同。开机时按住Shift(或者开机后快速按Esc)进入 GRUB 菜单,选中内核行按e编辑。
找到linux开头那一行,把其中的ro改成rw,然后在行尾追加:
init=/bin/bash按Ctrl+X启动后,系统会直接进入一个 root shell,而且根目录已经是可写模式,可以直接执行:
passwd root修改完成后,执行exec /sbin/init(或者直接reboot)返回正常启动流程。
这个方法的关键是把ro改成rw,否则根目录只读,你passwd会报错。另外,Ubuntu 默认是禁用 root 登录的(root 账号没有密码,只能通过 sudo 提权),如果你在机器上执行过sudo passwd root设置了密码,用这套方案也能正常重置。
3.3 救援模式 chroot 完整重置
如果系统已经损坏到连 GRUB 都进不去,或者你用的是服务器厂商的救援模式,那么要挂载系统盘到临时目录再 chroot 操作。
以 CentOS 安装 ISO 启动后,选择Rescue a broken system(救援模式),然后按提示选择已有 Linux 分区。系统会把你原来的根分区挂载到/mnt/sysimage,接着执行:
chroot /mnt/sysimage passwd root这里最容易翻车的点是:ISO 版本和系统原有版本差异不能太大。如果你用 CentOS 8 的 ISO 去 chroot 一个 CentOS 7 系统,动态链接库不兼容,chroot进去后很多命令直接报错。遇到这种情况,建议直接找同版本、同大版本的救援介质。
还有一个更通用的备用路子:在 LiveCD 或救援 shell 下直接编辑/etc/shadow,把 root 行第二个冒号后面的一长串 hash 清空。这样 root 账号变成无密码状态,系统启动后输入root回车就能直接进入。但这个方法非常危险,空密码意味着任何拿到交互终端的人都能直接空密码登入 root,所以进入系统后要立刻执行passwd root设置新密码,一秒都别拖。
4. 数据库 root 密码:换密码、找回密码与 1045 排查
4.1 MySQL/MariaDB 修改 root 密码的标准姿势
数据库 root 的密码修改,跟系统 root 完全是两个路子。先讲能正常登录的情况。
新版本 MySQL(5.7+)和 MariaDB 都推荐用ALTER USER语句:
ALTER USER 'root'@'localhost' IDENTIFIED BY '你的新密码'; FLUSH PRIVILEGES;MariaDB 10.4 之后有个坑:默认 root 账号使用unix_socket认证插件,也就是说你在系统 root 用户下直接执行mysql -u root可以免密登录,根本不需要数据库密码。这个机制的本意是让系统管理员在本地直接管理数据库,很多人第一次遇到会非常困惑——明明没设密码却能登进去,设了密码用-p反而报错。
如果你想给 MariaDB 的 root 配置传统密码认证(也就是无论从哪儿登录都要输入账号密码),需要这样处理:
ALTER USER 'root'@'localhost' IDENTIFIED VIA mysql_native_password USING PASSWORD('你的新密码'); FLUSH PRIVILEGES;这句话的意思是让 root 使用传统的mysql_native_password方式认证。执行完以后,mysql -u root -p输入密码才能登录。
如果是老版本的 MySQL(5.6 及更早),很多教程会让你用这种方式:
SET PASSWORD FOR 'root'@'localhost' = PASSWORD('你的新密码');这种方法在 MySQL 5.7 之后已经不建议使用了,因为PASSWORD()函数被废弃。到 MySQL 8.0,默认的认证插件变成了caching_sha2_password,如果你用很老的客户端或驱动连接,会报认证插件不兼容。解决办法是在客户端升级驱动,或者在创建用户时指定IDENTIFIED WITH mysql_native_password BY '密码',但这只是过渡方案,长期还是建议升级客户端。
4.2 忘了数据库 root 密码:skip-grant-tables 方案
数据库 root 密码忘了,最经典的应急手段是skip-grant-tables,就是让 MySQL 跳过权限表直接以无密码模式启动。完整流程如下:
- 停止数据库服务:
systemctl stop mysqldMariaDB 的话,服务名可能是mariadb。
- 以跳过权限表的方式后台启动:
mysqld_safe --skip-grant-tables --skip-networking &这里--skip-networking必须带上,因为一旦跳过权限表,任何人都能无密码连进来,这个参数能禁止网络 TCP 连接,只允许本机 socket 连接,避免把自己的数据库暴露在局域网里。
如果 MySQL 8.0 环境里没有mysqld_safe脚本,直接这样启动也可以:
mysqld --skip-grant-tables --skip-networking --user=mysql &- 此时直接进入数据库:
mysql -uroot注意不需要-p。
- 刷新权限表,让
ALTER USER语句生效:
FLUSH PRIVILEGES;- 修改密码:
ALTER USER 'root'@'localhost' IDENTIFIED BY '你的新密码';- 退出,重启数据库服务:
exit systemctl restart mysqld这一步很关键,必须重启服务。否则 MySQL 一直处于跳过权限表的模式运行,安全漏洞大开。
另一种更安全的方式是用--init-file。先写一个包含ALTER USER语句的 SQL 文件,然后让 MySQL 启动时自动执行:
cat > /tmp/mysql_reset.sql <<EOF ALTER USER 'root'@'localhost' IDENTIFIED BY '你的新密码'; EOF mysqld --init-file=/tmp/mysql_reset.sql --user=mysql &执行完成后删除这个 SQL 文件,再正常重启服务。这种方式的好处是启动过程不会跳过权限表,只是临时执行一次密码修改,相对更可控。
4.3 ERROR 1045 Access denied 排查思路
ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: YES)这个报错,是数据库 root 密码问题里最典型的一条。要注意,报错信息里明确告诉你它连接的是root@localhost,说明 MySQL 在权限表里找不到能匹配当前客户端来源的账号,或者密码校验失败。
常见原因不止“密码打错了”这一种,我列一个排查清单:
| 可能原因 | 判断方法 | 解决办法 |
|---|---|---|
| 密码确实输入错误 | 确认是否有大小写、空格、特殊字符问题 | 重置密码或找出正确密码 |
| Host 不匹配 | 查看mysql.user表中 root 对应哪些 Host | 确认连接方式,必要时新建root@'%'账号 |
| 账号密码已过期 | 查看password_expired字段是否为 Y | 执行ALTER USER ... ACCOUNT UNLOCK或重置密码 |
| 权限表未加载 | 是否长时间运行 skip-grant-tables 忘了重启 | 正常重启数据库 |
| 认证插件不兼容 | 查看plugin字段 | 更新客户端,或修改账号插件 |
排查时,如果你还能通过sudo mysql这种 socket 方式登录数据库,就先查几个字段:
SELECT user, host, plugin, password_expired, account_locked FROM mysql.user WHERE user='root';这个结果能帮你快速定位是认证插件问题、过期问题还是 host 匹配问题。
另外要注意,root@'localhost'和root@'127.0.0.1'在 MySQL 看来是两个不同的账号。如果你的客户端用 TCP 方式连接127.0.0.1,但权限表里只有localhost的账号,就可能出现“明明密码对,却报 Access denied”的情况。解决办法是确认客户端到底走的 socket 还是 TCP,并让账号的 Host 覆盖实际来源。
5. 密码安全与运维习惯:改完密码之后的事
5.1 密码复杂度与过期策略怎么设
改密码不是改完就完,还要让它“健康地活着”。Linux 系统的密码复杂度由 PAM 配置控制,在 RHEL/CentOS 系里主要看/etc/security/pwquality.conf,Debian/Ubuntu 系看/etc/pam.d/common-password关联的pam_pwquality或pam_cracklib。
常用的复杂度参数:
minlen = 12 dcredit = -1 ucredit = -1 lcredit = -1 ocredit = -1minlen表示最小长度,dcredit = -1表示至少包含 1 个数字,ucredit、lcredit、ocredit同理,分别表示大写字母、小写字母、特殊字符的最小数量。
密码过期策略用chage管理。给 root 设置 90 天过期、提前 7 天提醒:
chage -M 90 -m 7 -W 7 root查看当前状态:
chage -l root很多运维会忽略这个,结果到某一天批量出现“密码过期无法登录”的问题。如果团队对密码生命周期有硬性要求,建议在配置管理工具里统一管控,而不是靠人肉记忆。
5.2 用 SSH 密钥替代密码登录
root 密码最好只在应急时用,日常登录应该走 SSH 密钥。Linux 下生成密钥用:
ssh-keygen -t ed25519然后把公钥拷到服务器:
ssh-copy-id root@服务器IP以后登录就不再需要密码了。当你确认密钥可以正常登录后,再考虑修改 SSH 配置,把密码登录关掉:
vi /etc/ssh/sshd_config # 找到 PasswordAuthentication 改为 no systemctl restart sshd这一步有风险,一定要在确认密钥能登录之后再操作。我见过有人先关了密码登录,结果发现密钥失效,只能去机房或者云控制台救场。稳妥流程是:先生成密钥并验证能登录,再关闭密码登录,然后再测试一次密钥登录是否正常,最后才断开当前会话。
如果你使用云服务器,还要确保云控制台的 VNC 备用通道是开的,万一 SSH 配置改坏了,还能通过 VNC 进系统修复,不至于开不了机。
5.3 多年运维踩坑清单
最后分享一些我实际踩过的坑和养成的习惯:
- 改密码前先备份 shadow。执行
cp /etc/shadow /etc/shadow.bak.$(date +%F),万一写错还能回滚。 - 不要明文把 root 密码发到群里或邮件里。哪怕内网也不推荐,聊天记录和邮件日志会存很久。用密码管理平台分享或临时加密压缩包传递。
- 系统 root 密码和数据库 root 密码是两套体系,改的时候分开记录,混在一起后面必然后悔。
- 远程操作前先开一个 tmux 或 screen 会话。网络抖动导致 SSH 断了,tmux 里的操作还能继续,不至于半路卡死。
- 生产环境操作前做变更记录。改哪个系统、改什么、影响面多大、回滚方案是什么,写清楚再动手。
- 不要用弱密码。
root/123456这种密码在公网服务器上,基本活不过一晚上。至少用 16 位混合字符,或者直接用密钥登录跳过密码。
在实际处理这类问题的过程中,我最大的体会是:重置密码本身不难,难的是机制设计和应急演练。如果你在一个团队里,我强烈建议把 root 密码的保管方式从“某个人脑子里的密码”改成“密码管理平台里的凭据 + 密钥双因素”,并且每季度至少演练一次断密码场景。道理很简单:如果从没在慌乱中重置过 root 密码,等真出问题时花费的时间至少是平时的三倍。希望这篇把系统 root 和数据库 root 的修改、重置、排查全部覆盖的文章,能帮你少走一点弯路。