先交代一下背景:我是在凌晨处理一台托管的 CentOS 7 生产机时遇到这个需求的。当时手里没有安装 U 盘,机房也不在身边,远程控制台的虚拟光驱里只有一个旧的 Windows 镜像,而 root 密码因为人员交接问题已经没人知道了。系统本身能正常引导到 grub,但进不了系统,等于一把钥匙锁在屋里。折腾了大概二十分钟,用 grub 启动参数直接闯进紧急模式改掉了密码,整个过程完全没用 ISO 镜像。这篇文章就把这条路径完整拆开讲,包括原理、三个可用入口、每一步命令的意图,以及我在真实服务器上踩过的几个坑。
这件事适合任何手里没有安装介质、却需要重置 CentOS 7 root 密码的运维人员参考。无论你是服务器在机房、在云上只有 VNC 控制台,还是虚拟机里忘密码,只要 grub 还能出现,就有救。
1. 为什么没有 ISO 也能进救援模式:先搞清楚三条路径
很多人一听“救援模式”就默认必须有安装光盘或者 U 盘,其实这是被 CentOS 安装程序的 rescue 模式误导了。安装盘里的 rescue 模式只是一个方便操作的交互环境,它背后做的事情无非是:挂载硬盘根分区、chroot 进去、然后执行命令。既然原理是这个,那我们完全可以通过修改 grub 启动参数,在开机阶段直接实现同样的效果,根本不需要外部介质。
在 CentOS 7 上,无 ISO 进入救援环境的核心思路是通过 grub 给内核传递特殊参数,让系统在启动早期停在一个可控的 shell 里,然后手动挂载根分区、切 root、重置密码。具体有三条路径可走:
| 路径 | 启动参数 | 适用场景 | 难度 |
|---|---|---|---|
| rd.break | 在 linux16 行末尾追加 rd.break |
最通用,systemd 在切换根之前强制中断 | 简单 |
| init=/sysroot/bin/sh | 将 linux16 行中的 rhgb quiet 替换 |
直接跳过 systemd 初始化,进入 shell | 简单 |
| systemd.unit=rescue.target | 在 linux16 行末尾追加 |
系统能启动但服务异常时进入救援模式 | 中等 |
先说结论:我推荐优先用 rd.break。它是三条路里最稳定的,因为它在 systemd 完成根文件系统切换之前就停住了,这时候宿主机层面的干扰最小,几乎不会因为某个服务卡住导致你进不了 shell。而 init=/sysroot/bin/sh 则适合那些已经跑过 SELinux 重打标签、系统里服务比较多、怕 rd.break 挂载阶段出幺蛾子的场景。systemd.unit=rescue.target 则更接近“系统能起来但不想起全部服务”的运维场景,不完全是密码重置专用。
这里必须强调一个容易被忽略的前提:所有路径都要求你能看到、能编辑 grub 菜单项。如果你在本地服务器前,开机按住 Shift 或者不断按上下方向键就能看到菜单;如果在云平台或机房远程控制台,通常在“重启”时能通过 VNC 或 IPMI 看到 grub 界面。如果连 grub 都进不去,那说明引导已经损坏,那又是另一个故事了,这篇先不展开。
2. 准备条件确认:进入 grub 编辑界面的前置检查
不要一上来就敲命令,先花两分钟确认三件事,能帮你避开后面更深的坑。
2.1 确认启动方式是 BIOS 还是 UEFI
CentOS 7 同时支持 BIOS(传统 MBR)和 UEFI 启动。在 grub 菜单里,两者的界面略有差异,但编辑方式完全一样:选中你要启动的内核行,按 e 键。区别主要体现在如果你后续需要修复引导,分区路径会不一样。本次重置密码的操作路径基本一致,所以这一步主要是让你心里有个数。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2.2 检查 grub 是否设置了密码保护
有些安全加固文档会建议在 grub 里配置密码,防止别人在开机界面直接改启动参数。如果你管理的机器正好做了这个加固,那在按 e 之后会先弹出用户/密码输入框,没有密码就进不去编辑界面。这时候无 ISO 这条路就直接堵死了。
如果你曾经设置过 grub 密码但忘了,而且系统里还有 root 密码(能登录系统),那可以用 grub2-setpassword 之类的命令重置;但通常这个场景下 root 密码也没了,那就只能拆机或者找带外管理里的“上次进入 grub 时保存的内核参数”碰碰运气。真实环境里,大部分服务器不会单独设置 grub 密码,所以这个检查通常几秒钟就过。
2.3 确认根分区是否加密(LUKS)
如果装系统时选择了加密磁盘,那么直接 rd.break 后挂载根分区时会卡在解密步骤。系统会提示输入 LUKS 口令,而这个口令通常和 root 密码不是同一个,如果当初没有备份密钥文件,那无 ISO 救援也无法绕过硬件级加密。这一点必须提前确认清楚,别折腾了半天发现卡在盘锁上。
我遇到过一次,同事在安装时勾选了加密,结果 root 密码和 LUKS 口令都忘了,最后只能靠备份恢复。从那之后我负责的服务器一律不开启磁盘加密,或者必须把 recovery key 存到带外管理里。
3. 路径一:rd.break 参数直捣 emergency 模式(最稳定方案)
这是我实际使用最多的方案,操作步骤清晰,失败率低,适合绝大多数 CentOS 7 环境。
3.1 进入 grub 编辑界面
开机后到了 grub 菜单,选中你的内核(通常第一个),按 e。你会看到类似这样的文本:
bash复制setparams 'CentOS Linux (3.10.0-1160.el7.x86_64) 7 (Core)'
load_video
set gfxpayload=keep
insmod gzio
insmod part_gpt
insmod ext2
set root='hd0,msdos1'
...
linux16 /vmlinuz-3.10.0-1160.el7.x86_64 root=/dev/mapper/centos-root ro crashkernel=auto rhgb quiet
initrd16 /initramfs-3.10.0-1160.el7.x86_64.img
这里关键行是 linux16 开头那一行。用方向键把光标移到这行末尾,在 quiet 后面加一个空格,然后输入 rd.break。
添加完之后按 Ctrl+X 或者 F10 启动。系统会短暂黑屏,然后停在一个类似这样的 shell 里:
bash复制Generating "/run/initramfs/rdsosreport.txt"
Entering emergency mode. Exit the shell to continue.
Type "journalctl" to view system logs.
You might want to save "/run/initramfs/rdsosreport.txt" to a USB stick or /boot
for after mounting /sysroot and then reboot.
3.2 为什么 rd.break 能让我们改密码
简单理解一下:在内核启动到真正切换根文件系统之前,initramfs 会执行一系列 hook,rd.break 参数让它在执行完“解析根设备”和“挂载真实根”之间停下来。这时候系统实际的根目录还是 initramfs 在内存里展开的临时根环境,而你的真实硬盘根分区已经被探测到一个临时挂载点 /sysroot 下面,但是是只读挂载。
此时你拿到的是一个超级精简的 shell,很多命令不可用,但 mount、chroot、passwd 这些核心工具都在。我们要做的就是把这个 /sysroot 重新以读写方式挂载,再把当前环境切进去,就能像平常在系统里一样操作了。
3.3 具体操作步骤
第一步,把 /sysroot 重新挂载为可写。默认它是只读的,直接执行 passwd 会失败。
bash复制mount -o remount,rw /sysroot
注意这里原系统根分区在 sysroot 下,所以必须先 remount 为 rw,这个操作没有任何输出,成功就是静默的。
第二步,切 root 到这个临时挂载点:
bash复制chroot /sysroot
切换之后,你会看到提示符变了,比如从 ]# 变成 sh-4.2# 之类的。此时你已经“进入”了原来的系统:/etc、/home、/var 都是原系统的文件。
第三步,直接执行 passwd 重置 root 密码:
bash复制passwd root
系统会提示输入两次新密码。这里有个容易踩的细节:如果密码策略比较严格,比如设置了最小长度或者复杂度要求,输入过短密码可能被拒。 你可以临时设置一个高强度密码,比如大小写字母+数字+符号,后面再改。另外,生产环境建议重置后立即把新密码发给相关同事,避免再次出现“密码遗失在交接缝隙里”的情况。
第四步,SELinux 重打标签。这是绝对不能省略的一步,原因我在后面的章节专门讲。先执行:
bash复制touch /.autorelabel
第五步,退出 chroot 并重启:
bash复制exit
exit
reboot
第一个 exit 退出 chroot 环境,第二个 exit 退出紧急模式 shell,然后重启。也可以连按两次 Ctrl+D。
3.4 常见报错与处理
我见过不少人在第二步直接卡住,原因是忘了 remount,然后执行 chroot /sysroot 时报错说无法执行 /bin/bash。或者 chroot 进去了但执行 passwd 时提示 /etc/passwd 只读,就是少做了 mount -o remount,rw /sysroot。
还有一个容易被忽略的点:如果你改了 linux16 行末尾的参数,但启动后不是停在 shell,而是正常进了系统,那多半是参数没有真正追加成功。 检查一下是不是把 rd.break 写到了 initrd16 行后面,或者写到了别的行。这个参数必须和内核在同一行。
4. 路径二:init=/sysroot/bin/sh 直接用 shell 改密码
如果说 rd.break 是“到了门口停下来”,那 init=/sysroot/bin/sh 就是“进门之后直接进办公室”。它不经过 systemd,直接让内核启动完 initramfs 后用 /sysroot/bin/sh 作为第一个用户态程序。这在某些情况下比 rd.break 更直接,但也有自己的脾气。
4.1 修改方法
同样在 grub 编辑界面,找到 linux16 这一行,把行尾的 rhgb quiet 两个参数删掉(留着也行但会刷屏),然后改成:
bash复制init=/sysroot/bin/sh
完整效果类似:
bash复制linux16 /vmlinuz-3.10.0-1160.el7.x86_64 root=/dev/mapper/centos-root ro crashkernel=auto init=/sysroot/bin/sh
按 Ctrl+X 启动,系统会停在:
bash复制sh: can't access tty; job control turned off
$
注意你看到的提示符可能是 # 也可能是 $,取决于内核启动参数里有没有在 init= 前面加上 rd.break。正常不加前缀时,当前 root 是 /sysroot 挂载的根,但很多路径还是只读状态。
4.2 这里不同的一点
进入 shell 后,根文件系统已经挂载在 /sysroot 下,但和 rd.break 不同,此时 /sysroot 是只读挂载。所以仍然要先执行:
bash复制mount -o remount,rw /sysroot
chroot /sysroot
passwd root
这里实际上和 rd.break 后半段很像,但区别在于少了一层 initramfs 的转场,缺点是你拿到的 shell 非常糙,几乎没有任何服务、网络、模块,甚至连 PATH 都只有极简几个目录。不过改密码足够了。
4.3 什么时候优先选这条路径
我一般在 rd.break 的紧急模式里卡住、或者机器上有奇怪的 LVM 卷组扫描问题导致 /sysroot 挂载异常时,会退回到这条路径。它绕过了 systemd 的整套设备挂载逻辑,直接从 initramfs 切换过去,少了很多设备依赖。如果之前遇到 kernel panic 或者 initramfs 损坏,init=/sysroot/bin/sh 反而比 rd.break 更容易出结果。
不过事情都有两面。因为跳过了 initramfs 的正常收尾流程,这条路径下某些版本的内核可能不会执行 /.autorelabel 这个标记的检查,所以如果你改密码后直接重启,SELinux 可能不会自动重打标签。稳妥起见,执行完 touch /.autorelabel 之后,再重启前建议确认这个文件确实存在:
bash复制ls -l /.autorelabel
如果不存在,补一次。
5. 路径三:改 grub 默认引导进 single 模式的备用方案
除了上述两种“临场改参数”的方式,还有一种更“持久”的方案:直接把 grub 的默认启动项改成 single 模式,然后正常重启。这适合那种机器当前无人值守、只能远程重启,但你已经能通过控制台操作 grub 的情况。
5.1 修改 grub 配置
在 grub 编辑界面,不要只改当前启动参数,而是先在 linux16 行末尾追加 systemd.unit=rescue.target 或者 single,启动进入单用户模式。确认密码修改成功后,再回到系统里把 grub 默认配置改回来。
如果更彻底一点,可以在系统里(进入单用户模式后)修改 /etc/default/grub 文件,把 GRUB_CMDLINE_LINUX 这一行里增加 single 或 systemd.unit=rescue.target:
bash复制GRUB_CMDLINE_LINUX="crashkernel=auto rhgb quiet single"
然后重新生成 grub 配置:
bash复制grub2-mkconfig -o /boot/grub2/grub.cfg
注意 BIOS 和 UEFI 的输出路径不同,UEFI 下是:
bash复制grub2-mkconfig -o /boot/efi/EFI/centos/grub.cfg
5.2 这条路径的利弊
优点是改完配置文件后,即使你根本来不及按 e 编辑 grub 菜单,重启后也会自动进入 rescue.target;缺点是你需要在修改完后、重新生成 grub 配置前,确认不会影响下次正常启动——否则就变成“永久单用户模式”了。
实际操作中,我更愿意把它当作应急备用方案,而不是首选。毕竟在 grub 界面按 e 是几秒钟的事,改配置文件涉及重新生成 grub.cfg,万一生成过程出错,可能把引导搞坏,反倒得不偿失。
6. 改完密码后必做的收尾验证与 SELinux 避坑
很多教程到这里就结束了,但真实环境里,改完密码不等于万事大吉。下面这几件事是我每次必做的,省一步就可能出事。
6.1 为什么必须执行 touch /.autorelabel
在执行完 passwd root 之后,你已经在 chroot 环境里修改了 /etc/shadow 文件。这个文件在 SELinux 环境下是有安全上下文的,正常情况下由系统维护。但你现在是通过 initramfs 手动修改的,SELinux 上下文可能没有被正确标记,甚至可能因为文件上下文变成 unlabeled,导致重启后 SSH 登录被拒、本地登录也报错。
touch /.autorelabel 的作用是告诉系统重启后重新为所有文件打一遍 SELinux 标签。这个过程会在开机阶段自动进行,通常需要几分钟到十几分钟,取决于文件数量。打完标签后系统会自动重启或者提示你手动重启。
如果不打标签,最典型的症状是:重启后 root 密码明明是对的,但登录时报错 Permission denied,或者 SSH 直接连不上。很多人这时候会怀疑密码没改成功,其实问题出在 SELinux 上下文。
6.2 重启后先验证密码策略
重置完密码进入系统后,第一时间检查密码是否过期:
bash复制chage -l root
如果显示 Password expires 之类的信息,说明系统里有密码过期策略。在生产环境,很多加固基线会把密码有效期设成 90 天或 30 天,如果重置后的新密码本身已经很老了(比如你用的是记忆里某个旧密码),有可能会立即触发过期,导致下次登录又要求改密。如果需要避免这种情况,可以临时禁用过期:
bash复制chage -M 99999 root
或者设置一个明确的过期时间,按公司规范来。这一步不属于常规操作,但确实遇到过,尤其是一些券商、银行项目里。
6.3 验证 SSH 与 sudo
如果这台机器是远程管理的,重置完密码、重启进入系统后,先别急着做别的,用另一个终端窗口测试 SSH 登录是否正常。如果 SSH 登录有问题,优先检查 /var/log/secure 里的认证日志。还要确认 PermitRootLogin 配置是否允许 root 直接通过 SSH 登录,很多时候系统加固会把 root 远程登录关掉,这时候不是密码问题,需要从本地控制台登录再调整。
另外,如果是普通用户密码忘了,但 root 密码还记得,完全不需要用这篇的救援路径,直接在系统里:
bash复制sudo passwd username
就行。救援模式主要用于 root 密码本身丢失、或者系统无法正常启动的场景。
6.4 收尾还要注意这几件事
- 如果修改密码之前机器上跑了重要服务,比如数据库、Nginx、Docker,重启时会全部中断,建议提前和业务方打招呼,尽量在低峰期操作。
- 如果使用云服务器或带外管理平台,远程控制台可能存在键盘映射问题。美国键盘布局下,密码里的特殊字符可能输入错位,建议密码先设简单一点,进入系统后再通过 SSH 改复杂密码。
- 操作过程中要留意
linux16行里原来的参数是ro,如果忘记改成rw,后面 remount 那一步是能兜住的,但如果你用init=/sysroot/bin/sh又跳过了 remount,就有可能在 passwd 时写入失败。 - 修改完后,建议用
mount | grep sysroot检查挂载状态,确认没有遗留的只读挂载点。 - 如果这台机器有很多 LVM 逻辑卷,rd.break 下的
/sysroot可能不包含所有逻辑卷,chroot 进去之后要去/dev/mapper确认哪些卷组在线。
7. 无 ISO 场景下的其他替代方案:systemd 服务与旧内核
如果连 grub 编辑都不想碰,还有一个思路:通过在正常的系统启动流程里注入一个自定义服务来改密码。但这要求你能在系统上创建一个 systemd service 文件,说白了就是你已经能在系统里执行命令了,那还改什么密码?所以这个方案只适用于“能进系统但 root 密码错误导致 sudo 被限制”的边缘场景,实际价值有限。
更值得记住的是另一个技巧:利用旧内核引导。CentOS 7 默认保留最近几个版本的 kernel,如果当前内核有问题导致无法进入紧急模式,比如 initramfs 损坏,那可以在 grub 菜单里选一个旧内核启动,然后通过同样的参数编辑方式进入紧急模式。旧内核通常更保守,对硬件兼容性问题更少,这对某些比较老的服务器特别有用。
如果系统启动时报错 /dev/mapper/centos-root 找不到,那说明 LVM 元数据可能损坏或者驱动缺失,这种情况下即使进了紧急模式也挂载不了根分区。这时真正的救援可能是用 vgchange -ay 激活卷组,或者用 initramfs 里的 dracut 重新生成。这些内容已经离“无 ISO 重置密码”核心目标很远了,但它们是同一类故障树上的延伸。
8. 实际运维中我把这些经验沉淀成的检查清单
最后把我每次执行无 ISO 救援任务时的操作顺序整理成清单,方便你直接抄作业。
- 确认带外控制台或本地显示器能显示 grub 界面。
- 确认 grub 没有密码保护。
- 确认根分区没有 LUKS 加密,或你能拿到 recovery key。
- 在 grub 菜单中按 e,在
linux16行末尾追加rd.break。 - 启动后执行
mount -o remount,rw /sysroot。 - 执行
chroot /sysroot。 - 执行
passwd root,设置高强度新密码。 - 执行
touch /.autorelabel。 - 连续两次
exit退出并重启。 - 重启后等待 SELinux 自动重打标签完成。
- 登录验证 root 密码,检查
chage -l root确认密码未过期。 - 检查 SSH 配置,确认 root 远程登录状态。
- 确认业务服务全部恢复正常后,再通知业务方。
这里有个细节值得多说一句:第 4 步不要手滑把 rd.break 加到 initrd16 或者 linux16 之前的 set root 行。我见过有人把参数添加到 linux16 行最前面,结果内核直接报非法参数。正确位置永远是在 linux16 ... rhgb quiet 这一行末尾,加一个空格再写参数。
按照这套流程操作,我从打开控制台到密码重置完成,通常控制在三到五分钟内。实际耗时最多的往往不是命令行操作本身,而是等待系统重启和 SELinux 重打标签。如果你在操作过程中遇到具体报错,不要急着盲目重试,先确认是不是挂载读写权限的问题,绝大多数失败都出在这。
