☰
SSH登录报Permission denied?从ssh -v到服务端日志的完整排查指南
2026/9/30 8:43:01 网站建设 项目流程

1. 先分清"密码错了"还是"根本没走到密码验证这一步"

如果你跟我一样经常跟远程服务器打交道,那"Permission denied, please try again"这行提示估计早就不陌生了。说句实话,这东西出现的频率高到我都快把它当开机问候语了,但它背后的原因其实千差万别——密码不对会报这个,密钥不行会报这个,服务端配置有问题还是报这个。很多新手看到这行字就下意识觉得"我密码输错了",但实际排查下来,真正输错密码的情况反而只占一小部分。

我用个生活化的类比来解释一下。你在小区门口按门铃,里面传来一句"您哪位?我没听说过您"。这个回复放在不同场景下,可能是保安真的不认识你,也可能是保安今天换了人、访客名单被撕了、甚至是对讲机坏了导致他压根听不清你喊的什么。SSH的"Permission denied"也一样,只是server端统一对外说的一句"我不认你",至于为什么不认你,它不会在默认情况下告诉你。

先别急着改配置,第一步是把客户端日志等级拉起来,先确定这个"denied"发生在哪个阶段。最简单的办法就是登录的时候加一个-v参数,或者更暴力一点,直接上-vvv:

ssh -v user@your-server-ip ssh -vvv user@your-server-ip

别小看这一个参数。加了之后,SSH客户端会把整个握手过程的所有事件都打印出来,包括连上了哪个IP、交换了什么算法、用的是哪种认证方法。你在输出里会看到类似这样的内容:

debug1: Authentications that can continue: publickey,password debug1: Next authentication method: publickey debug1: Trying private key: /home/me/.ssh/id_rsa debug1: Authentications that can continue: publickey,password debug1: Next authentication method: password

这段输出的信息量非常大。它告诉你两件事:第一,服务器当前允许的认证方式有哪几种(第一行的publickey,password就是服务器愿意接受的方式);第二,客户端依次尝试了哪些方式。如果你看到Authentications that can continue后面列出的方式里压根没有password,那你密码输一万遍也是白搭,因为服务器根本不接受密码认证这条路。

我也遇到过不少朋友上来就改服务端配置,折腾半天最后发现是自己客户端指定了错误的私钥文件。先在客户端把日志打开,确认问题出在哪一层,这是整个排查过程里性价比最高的一步。

2. 密码登录被拒:三类最容易被忽视的配置级原因

如果ssh -v已经确认服务器允许密码认证,而且你确定密码也没输错,那问题大概率出在配置层。这里我按我平时排查的经验,把最常见的三类原因整理出来。

2.1 PasswordAuthentication 被关闭

这是最经典的一个坑。很多人为了让服务器更安全,按照网上教程把/etc/ssh/sshd_config里的PasswordAuthentication改成了no,结果自己也忘了这茬,下次登录的时候就莫名其妙被拒了。

这个配置项的含义是一刀切地允许或禁止密码认证。改成no之后,所有用户都不能用密码登录,只能走密钥。如果你恰好还没把公钥部署上去,那基本就是把自己锁在门外的节奏。

那怎么确认是不是这个原因?回到上面说的-v输出:

debug1: Authentications that can continue: publickey

如果你看到括号里只剩publickey,没有password,那十有八九就是PasswordAuthentication被关掉了。解决方式也简单,有权限的话直接改回yes,或者从有密钥的机器上登录进去改。这里我强调一句:改完配置文件之后,一定要先测试再重启服务,避免把自己锁死。正确的姿势是:

sshd -t

这个命令会校验配置文件的语法,如果有语法错误会直接报出来。确认无误后再重启:

sudo systemctl restart sshd # 或者 sudo service ssh restart

2.2 PAM 模块与 ChallengeResponseAuthentication 的联动影响

大部分老手都知道PasswordAuthentication,但很多人忽略了ChallengeResponseAuthentication这个兄弟配置项。在某些 Linux 发行版和 SSH 版本里,密码认证其实走的是键盘交互(keyboard-interactive)通道,而键盘交互又受 PAM 模块控制。如果ChallengeResponseAuthentication被设成了no,或者 PAM 配置出了问题,同样会出现密码明明正确却提示Permission denied的情况。

我遇到过一例非常典型的场景:一台 Ubuntu 18.04 服务器,用户密码没问题,PasswordAuthentication也是yes,但所有用户都登录失败,报 Permission denied。后来我用ssh -vvv user@server看了一眼输出,发现它卡在keyboard-interactive这个认证方法上,而且服务器端日志里出现了 PAM 相关的报错。

查了半天,最后发现是/etc/pam.d/sshd里有一行配置被某个安全加固脚本改动过,导致 PAM 无法正常校验密码。这种问题单看 SSH 配置是完全看不出来的,必须结合服务端日志才能定位到。

给普通用户一个更直观的判断方法:在ssh -v输出里,如果看到Next authentication method: keyboard-interactive,然后紧接着就 Permission denied,那你就要考虑 PAM 层面的问题了。

2.3 密码里带特殊字符的"灵异事件"

这个说出来你可能觉得不可思议,但我确实遇到过不止一次。用户密码里有$、!、&这类特殊字符,在终端里输密码的时候被 shell 或终端工具"吃掉"了一部分,导致实际发送到服务器的密码跟真实密码不一样。

比如密码是Passw0rd!$ecure,在某些终端环境或 SSH 工具里,!可能触发 shell 的历史替换,$开头的内容可能被当作变量解析。虽然很多终端不会在处理密码输入时启用这类功能,但如果你用的是某些较老的终端工具、或者密码是从其他地方复制粘贴进来的,粘进来的时候被中间层转义修改也不是完全没可能。

应对方法是啥?简单粗暴:优先使用支持直接交互输入密码的方式,不要通过sshpass这类工具把密码作为命令行参数传;如果要用sshpass,也一定注意转义问题。另外,我个人的习惯是确认密码本身没问题后,再考虑是不是特殊字符在作怪——别在没确认密码正确之前就去改服务器配置。

3. 密钥认证失败:权限、路径与 known_hosts 的连环坑

现在越来越多的同学用密钥登录,因为确实比密码方便也更安全。但密钥认证报Permission denied的频率,说实话一点都不比密码低。每次帮人排查这类问题,我基本上都会按下面这条链路走一遍。

3.1 目录和文件权限不对,私钥直接不生效

SSH 对密钥文件的权限要求非常严格,这是出于安全考虑——如果私钥文件权限太宽松,任何人都能读你的私钥,那密钥认证还有啥意义。OpenSSH 会直接拒绝使用权限过大的私钥文件。

具体标准是这样的:

  • ~/.ssh目录的权限必须是700(drwx------)
  • ~/.ssh/authorized_keys文件的权限必须是600(-rw-------)
  • 私钥文件的权限也应该是600,不能是644或更宽松的权限

这个规则很多从 Windows 转过来的同学特别容易踩坑。Windows 文件系统没有 Unix 那套权限模型,用某些工具生成的密钥文件上传到 Linux 服务器之后,默认权限可能是644甚至755,OpenSSH 直接拒绝使用。

如果你在-v输出里看到类似这句话:

debug1: Will attempt key: /home/me/.ssh/id_rsa debug1: Trying private key: /home/me/.ssh/id_rsa

然后下一行又出现了Authentications that can continue,而没有Server accepts key之类的字样,那基本可以断定服务器没接受这个私钥。这时候先在客户端这边检查一下本地私钥权限:

ls -la ~/.ssh/ chmod 700 ~/.ssh chmod 600 ~/.ssh/id_rsa

再去检查服务器端authorized_keys的权限,因为服务端同样对~/.ssh目录和authorized_keys文件权限敏感。我之前见过一个情况:服务端authorized_keys文件权限是664(组用户可写),结果 SSH 直接忽略了这个文件,怎么登录都提示 permission denied,改成600之后立刻恢复。

3.2 authorized_keys 文件的格式与换行坑

有一个问题特别隐蔽:当你把自己的公钥粘贴到服务器的~/.ssh/authorized_keys文件时,如果粘贴过程把公钥内容折行了、或者文件末尾没有换行符,可能导致公钥无法被正确解析。authorized_keys文件要求每行一条公钥,不能有换行截断,不能有多余的引号或特殊字符。

我还见过一种更隐蔽的情况:公钥内容看起来对,但实际粘贴进去的时候混入了不可见字符(比如全角空格)。这种情况下用cat看文件内容完全正常,但 SSH 解析就是不通过。

排查手段很笨但很有效:把authorized_keys文件清空,用命令行方式重新写入公钥,避免复制粘贴过程引入隐藏字符。

mkdir -p ~/.ssh chmod 700 ~/.ssh echo "ssh-rsa AAAA...你的公钥内容... user@host" >> ~/.ssh/authorized_keys chmod 600 ~/.ssh/authorized_keys

这里注意一下,公钥内容必须是完整的一行,不能有换行。你可以在本地用cat ~/.ssh/id_rsa.pub看输出,然后通过ssh-copy-id自动部署:

ssh-copy-id -i ~/.ssh/id_rsa.pub user@server-ip

ssh-copy-id这个工具比我手动粘贴省心得多,它自己会处理好权限问题,不需要我每次手动chmod。

3.3 重启实例或重装系统后主机密钥变化导致的拒绝

还有一种经常让人抓狂的情况:服务器之前用密钥登录是好的,某天突然重启或者从镜像恢复之后,再用原来的密钥登录就报 Permission denied。

这里涉及到一个概念叫"主机密钥"(host key)。SSH 协议在设计时,客户端会保存一份服务器的公钥指纹(就是known_hosts文件里那一堆内容),用于防止中间人攻击。当你重新安装系统、或者某些虚拟化平台重置了实例,服务器的主机密钥变了,客户端识别出"这跟我之前认识的服务器不是同一台",出于安全考虑就会拒绝连接。

这个报错信息其实很直白,通常会提示你:

WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!

但有些情况下,客户端配置了StrictHostKeyChecking的某些选项,或者利用某些跳板工具,错误信息会被简化,最终落在Permission denied上。如果你确认服务器的确是同一台、只是系统重装过,那解决方案是把known_hosts里对应的那一条删掉,重新连接:

ssh-keygen -R server-ip

这样就会清除known_hosts中关于这个 IP 的旧指纹记录,下次连接时重新接受新的主机密钥即可。

4. 服务端账户与软件层面的隐形因素

很多时候客户端这边查了半天都没问题,这时候就该把目光转向服务端了——账户本身的状态、远程管理工具的介入、甚至安全防护软件的行为,都会让 SSH 登录显示成同样的一句 Permission denied。

4.1 root 登录受限与 shell 异常

很多服务器默认配置下,PermitRootLogin是prohibit-password或者no。如果你习惯直接用 root 账号登录,而这个值是no,那无论你密码对不对,服务端一律拒绝。这种情况在-v输出里能看到Authentications that can continue列表中没有 password(或者有但随即被拒),而服务端日志里会有很明确的提示。

Shell 异常这个坑也值得单独拿出来说。我遇到过一次非常"诡异"的情况:用户反馈 SSH 登录被拒,但我用另一个账号能正常登录进去。查了半天,原来这个用户的登录 shell 在/etc/passwd里被改成了一个根本不存在或者没有执行权限的路径,SSH 在认证成功之后尝试启动 shell 失败,最终对外呈现的也是连接被中断或拒绝。

排查方法很简单:

cat /etc/passwd | grep username

看看该用户行最后一个字段(就是登录 shell)指向哪里。如果是/bin/false、/sbin/nologin、或者某个不存在的路径,那这个用户默认就是无法登录的。有些运维人员为了"禁用"某个账号,会把 shell 改成 nologin,但忘了这个账号可能还有业务用途。

4.2 fail2ban 等防护工具把人拉黑的连锁反应

这个东西我吃过好几次亏。服务器部署了 fail2ban 或者 DenyHosts,某个账号密码连续输错几次之后,IP 被临时封禁或服务被暂时锁住。结果是:你后面哪怕输入了完全正确的密码,同样也提示 Permission denied。

这种场景的排查尤其需要冷静。如果你已经确认密码、密钥、配置全都正确,但还是被拒,可以换个网络环境(比如用手机热点)试试。如果换了网络就正常了,那九成是当前 IP 被某种防护机制盯上了。到服务器上执行:

sudo fail2ban-client status sshd

就能看到哪些 IP 被 ban 了。还有一种相似的情况是 PAM 的pam_faillock或pam_tally2模块在起作用,连续失败后锁定账号,即使密码正确也没用。这时候用有权限的账号(比如从其他 IP 或控制台)解锁:

sudo faillock --user username --reset

说起这个,我强烈建议大家在遇到 SSH 登录问题时先看一眼系统时间是否准确。我知道这听起来跟问题毫无关联,但 SSH 协议里有时间戳校验机制,客户端与服务端时间偏差太大会导致认证过程中的某些校验步骤异常,表现出的错误同样五花八门。我排查过一起密钥登录"间歇性失败"的怪事,最后发现就是服务器时间漂移了。

4.3 SSH 服务的监听地址与防火墙策略

还有一个容易被忽略的点:sshd_config里的ListenAddress。如果服务器配置了多个 IP,而ListenAddress只绑定了其中一个,你连的是另一个 IP,连接可能直接超时,也可能在特定情况下出现认证异常。防火墙策略同理,某些安全组规则只允许某个来源 IP 访问 SSH 端口,其他来源一律拒绝或丢包。

这类问题的特点是:现象不稳定,有时候能通,有时候不能通;或者只有特定网络环境下才有问题。挨个检查一圈之后,建议用nc -vz server-ip 22先确认端口可达性,再去深究认证层面的原因。

5. 从 ssh -vvv 到服务端日志:一套完整的排查链路

前面聊了这么多具体的场景,这里我把自己平时碰到这个报错时执行的完整排查链路整理出来。越是这种看似简单的报错,越需要有章法地排查,否则很容易东一榔头西一棒子,浪费时间还找不到根因。

第一件事,永远先在客户端确认问题出在哪个阶段。执行:

ssh -vvv user@server-ip

重点关注三段输出:

  • 第一段是连接建立阶段,看 TCP 是否连通、版本协商是否正常。如果卡在这里,是网络层问题。
  • 第二段是算法协商和主机密钥验证,看是否报 host key 相关错误。如果卡在这里,是 known_hosts 或中间人问题。
  • 第三段是认证阶段,看Authentications that can continue列出了哪些方法。这里能直接判断是密钥问题、密码问题、还是服务器根本不给你用某些认证方式。

第二件事,确认客户端没问题后,立刻转到服务端查日志。Ubuntu/Debian 系列看:

sudo tail -f /var/log/auth.log

CentOS/RHEL 系列看:

sudo tail -f /var/log/secure

服务端日志包含的信息量远大于客户端。它会明确记录认证失败发生在哪一步,比如Invalid user xxx、Failed password for xxx、Connection closed by authenticating user xxx、error: maximum authentication attempts exceeded等等。这些不同的关键词对应的排查方向完全不同:

日志关键词说明排查方向
Invalid user用户不存在确认用户名是否拼写正确
Failed password密码验证失败确认密码、PAM 配置、特殊字符
Connection closed by authenticating user认证过程中连接被关闭检查密钥格式、authorized_keys 权限
maximum authentication attempts exceeded认证尝试次数超限客户端指定了大量无效密钥文件
Received disconnect from ...服务端主动断开检查防火墙、fail2ban、TCPWrapper

第三件事,如果日志里也没有明确线索,就需要做"最小化验证"。所谓最小化验证,就是绕过所有可能出问题的环节,用最原始的方式测试。比如:

  • 关闭客户端的~/.ssh/config配置影响,用ssh -F /dev/null user@server-ip绕过自定义配置。
  • 只指定一个密钥文件尝试登录:ssh -i ~/.ssh/id_rsa -o IdentitiesOnly=yes user@server-ip。
  • 绕开可能的网络因素,在服务器本机执行ssh user@localhost,测试本机上的 SSH 服务是否正常。

我之前排查过一例,客户端报 permission denied,但服务器本机ssh user@localhost正常。最后发现是客户端的~/.ssh/config里配了一个ProxyJump,流量被转发到了一个错误的中转服务器上,等于一直在跟错误的机器握手。这种问题不看配置根本不可能想到。

第四件事,如果以上全部正常,最后再考虑改配置。改配置前一定先做备份:

sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak.$(date +%F)

然后逐项确认关键配置:

sudo sshd -T | grep -E 'permitrootlogin|passwordauthentication|pubkeyauthentication|challengeresponseauthentication'

注意用sshd -T而不是直接cat配置文件。因为sshd -T会展开所有 include 文件的结果,输出的是 sshd 实际生效的配置,而不是表面看到的文件内容。很多配置文件里有Include /etc/ssh/sshd_config.d/*.conf这样的行,你改的是主配置文件,但某些配置项可能被追加配置文件覆盖了,这是 Linux 系新版 OpenSSH 特别常见的一个坑。

6. 我踩过的坑和最后的经验总结

按惯例,最后分享几个我实际遇到的、不在常规排查清单里的小众情况。

第一个是 SELinux 上下文问题。CentOS 7 以上如果开启了 SELinux,即使文件权限全对,SELinux 的安全上下文不对也一样登录不了。这种情况在tail -f /var/log/audit/audit.log里能看到denied相关的记录。我曾经帮朋友处理过一台服务器,所有配置检查了 N 遍都对,最后发现是根目录下.ssh目录的 SELinux 上下文不对,执行:

restorecon -R -v ~/.ssh

才彻底解决。这个问题坑就坑在普通排查手段根本看不到异常,只有看审计日志才能发现。

第二个是关于"多个公钥"的坑。有时候你本地~/.ssh下有好几个密钥文件,SSH 客户端默认会依次尝试所有密钥。如果第一个密钥被服务器拒绝,客户端不会立刻跳过,而是继续尝试下一个。但如果服务器配置了MaxAuthTries限制(默认是 6),尝试次数超过上限,即使最后一个密钥是正确的,也会被踢掉。解决方案是在客户端~/.ssh/config里明确指定使用哪个密钥:

Host myserver HostName 192.168.1.100 User myuser IdentityFile ~/.ssh/my_special_key IdentitiesOnly yes

第三个是关于 SSH 配置文件里PermitRootLogin和 PAM 的组合问题。有个版本比较老的操作系统上,即使设置了PermitRootLogin yes,如果 PAM 的/etc/pam.d/login里有pam_securetty模块拦着 root 从伪终端登录,root 依然登不上去。这时候securetty文件里需要添加对应的 tty 名称,或者把pam_securetty那行注释掉。

说了这么多,其实最核心的体会就一句话:Permission denied, please try again是 SSH 对外统一的一张"冷脸",它把内部的所有拒绝原因都掩盖了。不要在旁边瞎猜,按"客户端是否允许认证 → 密钥是否被认可 → 密码是否正确 → PAM 是否放行 → 防护策略是否拦路"这条链路逐级排查,配合ssh -vvv和服务端日志双管齐下,这个报错背后的真实原因基本没有藏得住的。最后再啰嗦一句:改任何服务端配置前先把用户和当前连接备份好,别把自己锁在门外,这是我见过最多、也最让人哭笑不得的"运维事故"了。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询