SSD Nodes Learn Hosting plans →
指南 Matt Connor作者: Matt Connor · 更新于 2026-08-21

修复 SSH Too many authentication failures 错误

SSH 代理会逐个提供已加载的密钥,超过服务器 MaxAuthTries 默认 6 次后断开连接。使用 ssh -v 定位顺序,并配置客户端仅提供正确密钥。

“Too many authentication failures”的含义

“Too many authentication failures”表示您的 SSH 客户端向服务器提供的密钥数量超过了服务器愿意检查的数量。服务器在尝试正确密钥之前就关闭了连接。这几乎总是客户端问题。密钥位于您的磁盘上,服务器已将其写入 authorized_keys,但这些事实都不起作用,因为连接过早结束。

具体过程如下。ssh-agent保存您已加载的所有私钥。客户端会逐个向服务器提供这些密钥,因为它无法知道该账户接受哪个密钥。服务器会拒绝不在 authorized_keys 中的密钥,并将每次拒绝都计为一次身份验证失败。sshd_config 中的 MaxAuthTries 限制了单个连接允许的失败次数。默认值为 6。如果您的代理中有 10 个密钥,而正确的密钥排在第 8 个,服务器会在尝试该密钥之前断开连接。

因此,解决方法是让客户端只提供一个密钥:正确的密钥。

服务器统计什么,以及 MaxAuthTries 的作用

公钥身份验证一开始就是一个逐个尝试的过程。客户端发送一个公钥,并询问服务器是否接受使用该密钥生成的签名。服务器回答是或否。“否”就是一次失败尝试,与密码错误完全相同。

sshd_config(5) 手册页说明了该限制:“指定每个连接允许的最大身份验证尝试次数。当失败次数达到该值的一半后,后续失败将被记录到日志中。默认值为 6。”

对于手动输入密码的用户,6 次尝试已经足够。对于持有 10 个密钥的代理,这个次数并不多。当失败次数超过限制后,sshd 会断开连接,并在系统日志中写入类似以下内容的一行:

error: maximum authentication attempts exceeded for deploy from 203.0.113.10 port 51292 ssh2

客户端会打印同一事件的另一部分:

Received disconnect from 203.0.113.10 port 22:2: Too many authentication failures
Disconnected from 203.0.113.10 port 22

这与 SSH permission denied(publickey)错误 不同。后一种情况下,服务器检查了你提供的所有内容,但没有接受任何一个。这里则是服务器停止了继续检查。将这两种情况混为一谈,就会让人花费一个下午重新复制一个本来就正确的密钥。

为什么同一个密钥在同事的笔记本上可以使用

密钥和服务器都没有变化。对方的代理中有 2 个密钥,而你的代理中有 12 个。对方的密钥会先被发送,而你的密钥要到第 9 个才会发送;这时连接已经超时。

密钥数量会在不知不觉中增加。AddKeysToAgent yes~/.ssh/config 中会将你使用的每个密钥添加到代理,并一直保留。桌面密钥环代理(例如 Linux 上的 GNOME Keyring 或 macOS 的登录钥匙串)会在登录时自动加载密钥,而不会询问你。经过一年的时间,你可能添加了客户端密钥、Git 主机密钥和实验室服务器密钥。某一天,一台一直可以连接的服务器开始拒绝你的连接。服务器没有任何变化,只是你的代理中保存的密钥更多了。

如何使用 ssh -v 查看提供的密钥

使用 -v 重现失败的连接,并查看跟踪输出。

ssh -v deploy@203.0.113.10

需要关注两类行。Will attempt key: 列出客户端已整理的身份,并按照实际使用顺序排列。每向服务器实际发送一个密钥,Offering public key: 就会出现一次。

debug1: Will attempt key: /home/you/.ssh/id_ed25519 ED25519 SHA256:AAAA... agent
debug1: Will attempt key: /home/you/.ssh/id_rsa RSA SHA256:BBBB... agent
debug1: Offering public key: /home/you/.ssh/id_ed25519 ED25519 SHA256:AAAA... agent
debug1: Authentications that can continue: publickey,password
debug1: Offering public key: /home/you/.ssh/id_rsa RSA SHA256:BBBB... agent

您的路径、密钥类型和指纹可能不同。需要统计的是断开连接前出现的 Offering public key: 行数。如果这些提供的密钥依次发送,但会话结束前始终没有出现您指定的密钥,原因就已确定。行末的 agent 表示该身份来自 ssh-agentexplicit 表示该身份来自 IdentityFile 行,或来自命令行中的 -i

然后查询 agent 当前持有的密钥:

ssh-add -l

输出中的每一行表示一个已加载的密钥。如果输出 The agent has no identities.,说明问题不在 agent,应改为检查 ~/.ssh/config 中的 IdentityFile 行。如果输出 Could not open a connection to your authentication agent.,说明没有运行 agent,提供的密钥来自默认密钥文件。

修复 1:每台主机只使用一个密钥并启用 IdentitiesOnly

IdentitiesOnly yes 会告知 ssh 只发送您配置的身份,并忽略 agent 主动提供的其他身份。将其与 IdentityFile 行配合使用后,客户端只会发送一次密钥尝试。

Host vps
  HostName 203.0.113.10
  User deploy
  IdentityFile ~/.ssh/id_ed25519_vps
  IdentitiesOnly yes

将该配置保存到 ~/.ssh/config,然后运行 chmod 600 ~/.ssh/config。如果文件允许组用户或其他用户写入,ssh 会拒绝运行,并显示 Bad owner or permissions on /home/you/.ssh/config。此时,ssh vps 只会提供一个密钥,而 ssh -v vps 应准确显示一行 Offering public key:

这里有两个容易令人困惑的细节。

  • IdentitiesOnly yes 单独使用并不表示“一个密钥”。默认身份文件也会计入已配置的身份,因此 ssh 仍会尝试 ~/.ssh/id_ed25519~/.ssh/id_rsa 以及找到的其他默认文件。您还需要 IdentityFile 行。
  • 签名仍由 agent 执行。IdentitiesOnly 控制提供哪些密钥,而不是由谁执行签名。如果 IdentityFile 指定的私钥已加载到 agent 中,agent 会生成签名,您不会被要求输入密码短语。您甚至可以将 IdentityFile 指向匹配的 .pub 文件;当私钥只存在于 agent 或硬件令牌中时,应采用这种配置。

~/.ssh/config 中有一个陷阱会悄悄使此修复失效。大多数关键字使用首次找到的值,因此特定的 Host 块应放在 Host * 之前。IdentityFile 不遵循此规则。手册说明:“可以在配置文件中指定多个身份文件;所有这些身份都会依次尝试。”在 Host * 下设置的 IdentityFile 会追加到每台主机的配置,而不是替换它,因此遗留的全局配置行会让每次连接再次发送额外的密钥。

如果您希望设置全局安全保护,只在文件末尾设置该标志:

Host *
  IdentitiesOnly yes

之后每台主机都需要单独设置 IdentityFile,这本来就是您希望达到的结果。为每台服务器指定一个密钥,也能让您在以后撤销某台机器的访问权限,而无需重新签发所有密钥。这种习惯应尽早建立:请参阅如何按机器管理 SSH 密钥

修复 2:清理或重启代理

如果暂时无法编辑配置,请清空代理,只加载所需的密钥。

ssh-add -l                    # list what is loaded
ssh-add -d ~/.ssh/id_rsa      # remove one key
ssh-add -D                    # remove every key
ssh-add ~/.ssh/id_ed25519_vps # load the one you need

如果执行 ssh-add -D 后连接立即恢复,说明问题由代理导致。但应将此视为测试,而不是修复。桌面密钥环代理会在您下次登录时重新加载密钥,因此问题明天还会出现。~/.ssh/config 中的 IdentitiesOnly 行会在重启后保留。空代理不会保留。

您也可以为密钥设置有效期,让代理自动清除该密钥:

ssh-add -t 1800 ~/.ssh/id_ed25519_vps

密钥添加后 1800 秒会被删除。重启代理同样有效,具体操作取决于启动代理的方式。您自行启动的 ssh-agent 可使用 ssh-agent -k 停止。如果您通过自行编写的 systemd 用户单元运行它,请使用 systemctl --user restart <unit> 重启该单元。密钥环代理会随桌面会话重启。

修复 3:仅连接一次的服务器使用一次性命令

对于不会添加到配置文件的主机,将相同设置直接放在命令行中:

ssh -o IdentitiesOnly=yes -i ~/.ssh/id_ed25519_vps deploy@203.0.113.10

单独使用 -i 是最常见的错误修复方式。-i 会将一个密钥添加到身份列表中,但不会从该列表中移除 agent 的密钥。因此,其他密钥仍会先于你的密钥发送,连接仍会在达到限制时失败。不使用 IdentitiesOnly 运行 ssh -v -i ~/.ssh/id_ed25519_vps deploy@203.0.113.10 时,你会看到 agent 的密钥先被发送。-i 需要与 -o IdentitiesOnly=yes 一起使用。

要在一次连接中完全停用 agent:

ssh -o IdentityAgent=none -i ~/.ssh/id_ed25519_vps deploy@203.0.113.10

此时,ssh 会直接从磁盘读取私钥;如果私钥设置了密码短语,ssh 会提示输入该密码短语。

基于 ssh 构建的工具也接受相同的选项:

scp -o IdentitiesOnly=yes -i ~/.ssh/id_ed25519_vps report.tar.gz deploy@203.0.113.10:/tmp/
rsync -av -e "ssh -o IdentitiesOnly=yes -i ~/.ssh/id_ed25519_vps" ./site/ deploy@203.0.113.10:/srv/site/
GIT_SSH_COMMAND="ssh -o IdentitiesOnly=yes -i ~/.ssh/id_ed25519_vps" git clone git@example.com:team/repo.git

第二跳出现错误的原因

使用 ForwardAgent yes 时,agent socket 会在您连接到的服务器上提供。该服务器上运行的 ssh 命令会通过转发的 socket 使用您本地的 agent 及其中的所有密钥。因此,从跳板主机连接到最终服务器时可能出现错误,而第一跳仍然正常。在中间机器上运行 echo $SSH_AUTH_SOCK:如果输出 socket 路径,说明可以访问转发的 agent;如果输出为空,说明没有转发的 agent。

agent 转发还会带来第二个风险。只要会话仍处于打开状态,中间机器上拥有 root 权限的任何人都可以使用您的 agent,以您的身份进行身份验证。ProxyJump 可以同时避免这两个问题:

ssh -J deploy@jump.example.com deploy@10.0.0.5

ProxyJump 会通过跳板主机建立连接,并从您自己的机器向最终服务器进行身份验证。因此,您本地的 ~/.ssh/config 会应用于每一跳,包括 IdentitiesOnly。关闭 ForwardAgent加固 VPS 上的 SSH时的标准步骤。

应提高服务器上的 MaxAuthTries 吗?

通常不应提高。先检查当前值:

sudo sshd -T | grep -i maxauthtries

sshd -T会打印实际生效的配置,其中包括默认值。因此,即使 sshd_config 没有相关设置,它也会报告真实值。如果使用 Match 块,请添加 -C user=deploy,host=example.com,addr=203.0.113.10,因为这些块会按连接进行评估,否则会被跳过。

提高限制确实有效,但作用很有限:更大的数值只会给行为异常的客户端更多尝试空间:

MaxAuthTries 20

验证文件并重新加载服务。执行此操作时,保留第二个会话处于打开状态:

sudo sshd -t
sudo systemctl reload ssh      # Debian and Ubuntu
sudo systemctl reload sshd     # RHEL family

如果在 Ubuntu 24.04 上,systemctl is-enabled ssh.socket 报告 enabled,则 sshd 由 socket 激活:每个连接都会启动一个新进程,并再次读取 sshd_config,因此新连接会自动使用更改后的配置。

现在检查这项更改的实际效果。客户端正在提供服务器永远不会接受的密钥。提高上限后,服务器会为每个连接处理 20 个被拒绝的密钥,而不是 6 个;这适用于所有连接到服务器的客户端,也适用于互联网上的每个密码猜测者。每个密钥都会导致服务器在 authorized_keys 中执行一次查找。您的登录速度仍然很慢,因为正确的密钥仍排在最后。向 agent 中再添加第 13 个密钥后,问题会回到原点,您又需要请求提高限制。

只有在合法客户端确实需要提供多个身份时,才提高该值。其他情况下都应修复客户端配置。当每个用户都使用已配置的密钥登录后,可以将其降低作为合理的加固措施,因为较小的数值会减少每个连接中猜测者可进行的尝试次数。

fail2ban 为什么会因此封禁您的地址

在默认日志级别下,sshd 会记录每次被拒绝的公钥:

Failed publickey for deploy from 203.0.113.10 port 51292 ssh2: ED25519 SHA256:AAAA...

使用已加载多个密钥的 agent 建立一次连接时,同一地址可能会在 1 到 2 秒内产生多条此类日志。fail2ban 的 sshd jail 会统计 sshd 的失败日志行;当在 findtime 内达到 maxretry 时,就会封禁源地址。默认时间窗口较短,因此损坏的连接重试两次,就可能封禁您自己的地址。

此时症状会发生变化,这也是最容易造成困惑的地方。您不再看到 “Too many authentication failures”,而是完全看不到响应:连接一直挂起,最终超时。这是因为防火墙现在直接丢弃数据包,而不是返回错误。原本会收到错误消息,现在却变成连接超时,这就是判断信号。相关区别请参阅 SSH 连接被拒绝与连接超时的区别

通过服务提供商的控制台,或使用其他地址,检查 jail 并解除封禁:

sudo fail2ban-client status sshd
sudo fail2ban-client set sshd unbanip 203.0.113.10

排查客户端问题期间,将您自己的地址添加到 ignoreipjail.local 中;完成后再将其移除。jail 本身的配置请参阅 Ubuntu 24.04 的 fail2ban 指南

一次性处理,避免问题反复出现

~/.ssh/config 中为每台服务器配置独立的 Host 块,并设置 HostNameUserIdentityFileIdentitiesOnly yes。完成后,ssh vps 命令很短,输入方便,只提供一个密钥,即使 agent 中的密钥很多,也不会触发 MaxAuthTries。这样,在其他故障发生时,ssh -v 的输出仍然足够简短,便于阅读。

FAQ

现在如何修复“身份验证失败次数过多”?

不要提供所有密钥,只提供一个密钥。要立即建立连接,请运行 ssh -o IdentitiesOnly=yes -i ~/.ssh/your_key user@host。要永久修复,请在 ~/.ssh/config 中添加一个配置块,其中使用 HostNameUserIdentityFile 指定该密钥,并添加 IdentitiesOnly yes,然后运行 chmod 600 ~/.ssh/config。使用 ssh -v 确认:您应看到该主机对应的一行 Offering public key:

为什么使用 ssh -i 后仍会提供其他密钥?

因为 -i 只是将一个身份添加到列表中,不会限制列表。加载到 ssh-agent 中的密钥仍在列表中,并且仍会被提供,通常还会排在您的密钥之前。因此,服务器可能会在轮到您的密钥之前达到 MaxAuthTries-o IdentitiesOnly=yes 才是用于限制 ssh 仅使用指定身份的选项。将 -i-o IdentitiesOnly=yes 一起使用,或者在这次连接中使用 -o IdentityAgent=none 完全忽略代理。

是否应增大服务器上的 MaxAuthTries 来修复此问题?

不应这样做,几乎所有情况下都不应这样做。客户端正在发送服务器永远不会接受的密钥。增大限制只会让服务器在每次连接中评估更多被拒绝的身份验证请求,包括来自所有客户端以及所有到达该服务器的暴力破解尝试的请求。只要代理中再加载一个密钥,问题就会再次出现。如果您想查看当前生效的值,请使用 sudo sshd -T | grep -i maxauthtries,然后使用 IdentitiesOnly 修复客户端配置。

为什么上个月运行正常的服务器现在开始出现此问题?

因为您的代理中加载了更多密钥。AddKeysToAgent yes 中的 ~/.ssh/config 会让您使用的每个密钥都保持加载状态,桌面密钥环代理还会在登录时自动加载密钥。当加载的密钥数量超过服务器的 MaxAuthTries 后,凡是目标密钥在提供顺序中较晚的服务器都会开始失败。运行 ssh-add -l,并将数量与服务器上的限制进行比较。

这会导致 fail2ban 封禁我的 IP 地址吗?

会。每个被拒绝的密钥都会在服务器日志中生成一行 Failed publickey for ...。因此,一次连接就可能在几秒内从您的地址产生多次失败,fail2ban 的 sshd jail 会在 maxretry 次失败在 findtime 内达到后封禁该地址。明显迹象是错误变成卡住,随后超时,因为数据包被丢弃而不是得到响应。使用 sudo fail2ban-client set sshd unbanip <your address> 从控制台解除封禁,然后先修复客户端,再重新连接。

#SSH#ssh-agent#openssh#ssh-config#troubleshooting