SSH 出现 Permission denied (publickey) 怎么修复
Permission denied (publickey) 通常对应5种故障。用 ssh -v 查看用户名、服务器支持的方法和实际发送的密钥,定位问题并修复,避免误改配置导致无法登录。
Permission denied (publickey) 的实际含义
Permission denied (publickey) 表示您的客户端发送了一个或多个公钥,但服务器一个也没有接受。网络连接正常,sshd 也在运行:拒绝发生在身份验证的最后一步。修复方法不应靠猜测,因为 ssh -v 会告诉您具体属于 5 种原因中的哪一种。
括号中的内容表示服务器愿意接受的身份验证方法。单独出现 Permission denied (publickey) 表示该服务器已关闭密码登录,因此没有密码验证可供回退。出现 Permission denied (publickey,password) 表示服务器提供了密码验证,但您同样未通过密码验证。
一条消息涵盖 5 种不同故障,而且故意保持模糊。如果服务器回复“用户不存在”或“未安装该密钥”,就会帮助扫描有效账户的人员。因此,不要一开始就更换密钥和编辑配置文件。运行一条命令,读取 3 行输出,5 种可能原因就会缩小为 1 种。
先运行 ssh -v,并阅读以下三行
在失败的命令后添加 -v,然后重新运行:
ssh -v deploy@203.0.113.10以下是一个经过删减但符合实际的输出:
OpenSSH_9.6p1 Ubuntu-3ubuntu13, OpenSSL 3.0.13 30 Jan 2024
debug1: Connecting to 203.0.113.10 [203.0.113.10] port 22.
debug1: Connection established.
debug1: Authenticating to 203.0.113.10:22 as 'deploy'
debug1: Authentications that can continue: publickey
debug1: Next authentication method: publickey
debug1: Will attempt key: /home/you/.ssh/id_ed25519 ED25519 SHA256:0eL/8sBw... agent
debug1: Offering public key: /home/you/.ssh/id_ed25519 ED25519 SHA256:0eL/8sBw... agent
debug1: Authentications that can continue: publickey
debug1: No more authentication methods to try.
deploy@203.0.113.10: Permission denied (publickey).这三行包含了所需的全部信息。
Authenticating to 203.0.113.10:22 as 'deploy' 是实际使用的用户名。它不一定是您想使用的用户名,而是 ssh 根据命令行、~/.ssh/config 或本地登录名确定的用户名。
Authentications that can continue: publickey 是服务器接受的方法列表,在尝试任何密钥之前发送。如果第一份列表中缺少 publickey,说明服务器已关闭公钥登录,因此任何密钥都无法生效。
Offering public key: ... 每个密钥对应一行,显示密钥来源文件及其 SHA256 指纹。没有对应 Offering 行的密钥从未发送到服务器。
现在将问题分成两类:
- 没有与预期密钥对应的
Offering public key行。问题出在您的计算机上,因为服务器根本没有收到您的密钥。 - 客户端提供了密钥,但随后再次出现
Authentications that can continue: publickey。服务器收到了该密钥,但拒绝了它,因此问题出在服务器上。
以下原因按实际出现的频率排序。
原因 1:连接时使用了错误的用户名
最常见的原因也是最简单的原因。sshd(SSH 安全 Shell 服务器守护进程)不会告诉您某个账户不存在。它会使用这个虚构的用户名完成整个交互流程,最后返回相同的错误消息,因为泄露有效账户名会帮助攻击者。用户名拼写错误看起来与密钥损坏完全相同。
先检查 Authenticating to ... as 行。如果其中显示的是您笔记本电脑上的登录名,而不是服务器账户名,说明您在命令中省略了用户名。
ssh -v deploy@203.0.113.10
ssh -v root@203.0.113.10默认账户取决于云服务提供商构建的镜像。截至 August 2026,Ubuntu 云镜像通常提供 ubuntu 账户,Debian 镜像提供 debian 或 admin,Rocky Linux 和 AlmaLinux 提供 rocky 和 almalinux,许多 VPS 提供商则会直接将您的密钥安装到 root。提供商的控制面板会记录它创建的账户。您无法从服务器外部运行命令来查询该信息。
~/.ssh/config 中的 Host 块也会设置用户名,并且其优先级高于您本地的登录名:
Host vps-prod
HostName 203.0.113.10
User deploy如果您自行创建了账户,但随后无法使用该账户登录,密钥很可能只安装到了镜像的默认用户账户中,并未复制到新账户。这是新 VPS 上前 10 分钟内的操作,很容易遗漏。
原因 2:您以为发送的密钥并不是实际发送的密钥
默认情况下,ssh 只会提供 ssh-agent 中保存的密钥,以及 ~/.ssh 中一组固定文件名对应的密钥:id_ed25519、id_ecdsa、id_rsa,以及这些文件名对应的硬件和 DSA 变体。保存为 ~/.ssh/vps-prod 的密钥不会被 ssh 自动发现,除非您明确指定它。这就是详细输出中没有该密钥的 Offering public key 行的原因。
指定该文件,并阻止代理密钥替代它:
ssh -i ~/.ssh/vps-prod -o IdentitiesOnly=yes deploy@203.0.113.10仅使用 -i 还不够,因为代理中保存有密钥时,ssh 仍会先提供代理密钥,最后才提供指定的文件。这一点很重要,因为服务器会将每个被拒绝的密钥都计入 MaxAuthTries,其默认值为 6。代理中如果保存了 7 个密钥,可能会在尝试正确密钥之前耗尽该限制,随后提示信息会变为:
Received disconnect from 203.0.113.10 port 22:2: Too many authentication failuresIdentitiesOnly=yes 会将尝试限制为您传入的文件。使用 ssh-add -l 列出代理当前保存的密钥;如果代理中积累了多年的旧密钥,则使用 ssh-add -D 清除它们。然后将这些设置写入配置文件,避免下次登录时依赖记忆命令行选项:
Host vps-prod
HostName 203.0.113.10
User deploy
IdentityFile ~/.ssh/vps-prod
IdentitiesOnly yes客户端还有一个容易忽略的问题。如果您本机上的其他账户可以读取私钥,ssh 会拒绝使用该密钥。它会显示警告,然后忽略该密钥。因此,该密钥不会被提供,服务器也不会收到它:
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@ WARNING: UNPROTECTED PRIVATE KEY FILE! @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
Permissions 0644 for '/home/you/.ssh/vps-prod' are too open.chmod 600 ~/.ssh/vps-prod 可以修复权限问题。通过 USB 闪存盘或 Windows 共享复制密钥,通常会导致文件权限模式丢失。有关密钥的存放位置和命名方式,请参阅 SSH 密钥管理基础。
原因 3:公钥从未写入 authorized_keys
如果 ssh -v 显示密钥已发出,但服务器仍然拒绝连接,接下来应确认该密钥是否位于账户的 authorized_keys 文件中。由于无法通过 SSH 登录检查,请打开服务商的控制台进行确认。
sudo ls -l /home/deploy/.ssh/
sudo ssh-keygen -lf /home/deploy/.ssh/authorized_keys在 authorized_keys 文件上运行 ssh-keygen -lf,会为每个条目输出一个指纹:
256 SHA256:0eL/8sBw... you@laptop (ED25519)
3072 SHA256:9Tq2yZk... old-laptop (RSA)将这些指纹与 Offering public key 行中的指纹进行比较。如果列表中没有对应指纹,说明该密钥未安装到该账户,无论您记得自己执行过什么操作。
以下 4 种情况都很常见:
- 您粘贴的是私钥,而不是
.pub文件。公钥行以ssh-ed25519或ssh-rsa开头。私钥以-----BEGIN OPENSSH PRIVATE KEY-----开头。 - 粘贴内容被换成了多行。每个条目必须完整占用一行,否则换行后的密钥会被解析为多个损坏的条目,无法匹配。
- 密钥被写入
/root/.ssh/authorized_keys,但您以deploy登录,或情况相反。该文件按账户分别保存,不存在共享文件。 - 服务商的“添加我的密钥”输入框只将密钥写入镜像的默认用户,因此您之后创建的账户的
.ssh目录为空。
在控制台中以 root 身份添加密钥的安全方式如下:
sudo install -d -m 700 -o deploy -g deploy /home/deploy/.ssh
sudo tee -a /home/deploy/.ssh/authorized_keys >/dev/null <<'EOF'
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIExampleKeyDataHere you@laptop
EOF
sudo chown deploy:deploy /home/deploy/.ssh/authorized_keys
sudo chmod 600 /home/deploy/.ssh/authorized_keys之后再次运行 sudo ssh-keygen -lf /home/deploy/.ssh/authorized_keys。新的指纹现在应出现在列表中。如果仍有一台机器可以使用密码登录,ssh-copy-id -i ~/.ssh/vps-prod.pub deploy@203.0.113.10 可以执行相同操作,并为您正确设置权限。
原因 4:权限过于宽松时,sshd 为什么会忽略 authorized_keys
StrictModes yes 是 sshd 的默认设置。在此设置下,如果该文件、.ssh 目录或账户的主目录可被所有者以外的任何用户写入,sshd 就会拒绝读取 authorized_keys。原因很直接:如果组用户或其他用户可以写入您的主目录,拥有该权限的任何账户都可以替换 authorized_keys,接管登录。sshd 会将不可信路径视为不存在密钥。
客户端只会显示普通的 Permission denied 消息。服务器日志会记录实际原因:
Authentication refused: bad ownership or modes for directory /home/deploy/.ssh如果问题出在文件本身,日志通常为:
Authentication refused: bad ownership or modes for file /home/deploy/.ssh/authorized_keyssshd 接受的权限设置:
- 主目录:不可由组用户写入,也不可由其他用户写入。
755、750和700均可通过检查。775和777无法通过。 ~/.ssh:权限为700。~/.ssh/authorized_keys:权限为600。- 所有权:这三者都必须归您用于登录的账户所有,不能归 root 所有。
所有权与权限模式同样重要。/home/deploy/.ssh 中由 root 所有的文件也会无法通过相同检查。如果您使用 sudo nano 创建文件后忘记将所有权改回,就会出现这种情况。一次修复两项设置:
sudo chown -R deploy:deploy /home/deploy/.ssh
sudo chmod 700 /home/deploy/.ssh
sudo chmod 600 /home/deploy/.ssh/authorized_keys
sudo chmod go-w /home/deploy
ls -ld /home/deploy /home/deploy/.ssh最后一条命令会显示结果。主目录应使用 drwxr-xr-x 或更严格的权限,.ssh 应使用 drwx------。如果您还不清楚这些字符串的含义,请先阅读如何读取 drwxr-xr-x 这样的权限字符串,再在运行中的服务器上修改权限模式。
在 Rocky Linux 和 AlmaLinux 上,还应将 SELinux(安全增强型 Linux)列入排查范围。通过特殊方式创建的 .ssh 目录可能带有错误的文件标签,因此即使权限模式正确,sshd 仍会被拒绝读取。sudo restorecon -Rv /home/deploy/.ssh 会恢复正确的标签,sudo ausearch -m avc -ts recent 可显示是否是 SELinux 拒绝了访问。
原因 5:sshd 配置为拒绝您的连接
在当前的 Ubuntu 或 Debian 系统上,仅查看 /etc/ssh/sshd_config 并不够。该文件以 Include /etc/ssh/sshd_config.d/*.conf 开头,而 OpenSSH 对任何设置都会采用首次找到的值。因此,诸如 50-cloud-init.conf 这样的 drop-in 文件会先于主配置文件中更靠后的内容读取,并覆盖您在主文件中的修改。这就是为什么修改看似正确,却完全不起作用。
让 sshd 输出它实际使用的配置:
sudo sshd -T | grep -Ei 'pubkeyauth|authorizedkeysfile|permitrootlogin|allowusers|allowgroups|denyusers'正常输出应类似于:
permitrootlogin prohibit-password
pubkeyauthentication yes
authorizedkeysfile .ssh/authorized_keys .ssh/authorized_keys2检查您自己的输出时,重点关注以下内容:
pubkeyauthentication no。系统永远不会接受任何密钥。在ssh -v中,这也会表现为第一个Authentications that can continue:列表中没有publickey。authorizedkeysfile指向其他位置,例如/etc/ssh/authorized_keys/%u。此时,主目录中的文件会被完全忽略,原因 4 中的权限规则将改为应用于新路径。- 存在
allowusers或allowgroups。未列出的账户会因完全相同的错误被拒绝,且不会显示其他说明。denyusers和denygroups的作用相反。 - 当您尝试以 root 身份登录时存在
permitrootlogin no。prohibit-password是更实用的中间设置:root 可以使用密钥,但不能使用密码。
普通的 sshd -T 输出不会显示 Match 块,因为其结果取决于发起连接的用户。请针对某个具体连接进行查询:
sudo sshd -T -C user=deploy,host=vps.example.com,addr=198.51.100.7还有一个设置会影响较旧的密钥。OpenSSH 8.8 默认停止接受 SHA-1 签名(ssh-rsa),因此,多年来一直正常工作的 RSA 密钥可能会在服务器升级后立即失效。客户端会明确显示原因:
debug1: send_pubkey_test: no mutual signature algorithm正确的解决方法是生成新密钥:ssh-keygen -t ed25519 -C "deploy@vps-prod",然后按上文所示安装 .pub 文件。在服务器上设置 PubkeyAcceptedAlgorithms +ssh-rsa 可以重新启用旧签名,让您今天先登录服务器。因此,应将其视为临时进入服务器的手段,而不是最终解决方案。其他值得检查的服务器端设置,见加固 VPS 上的 SSH 服务器。
如何证明私钥与已安装的公钥匹配
出现此错误时,很多问题在于无法确定两个文件是否配对。使用一个命令即可确认:
ssh-keygen -y -f ~/.ssh/vps-prod该命令会输出从私钥派生出的公钥。它不会读取旁边的 .pub 文件,因此显示的是私钥实际对应的公钥,而不是过期的 .pub 文件所声明的内容。如果密钥设置了密码短语,命令会要求输入密码短语。这也能证明您仍然知道该密码短语。
ssh-keygen -lf ~/.ssh/vps-prod.pub
ssh-add -l第一个命令会输出一个公钥文件的指纹。第二个命令会输出代理当前持有的指纹。现在对照同一字符串的4个结果:ssh -v 输出中 Offering public key 行的指纹、您的 .pub 文件的指纹、服务器 authorized_keys 上 ssh-keygen -lf 中的指纹,以及服务器日志中的指纹。它们从哪一处开始不一致,问题就出在哪里。
读取登录失败时的服务器日志
客户端有意不会收到有用信息。服务器会记录真实原因。在控制台会话中启动日志跟踪,然后从笔记本电脑运行失败的 ssh 命令。
sudo journalctl -u ssh -fUbuntu 24.04 默认不安装 rsyslog,因此那里可能不存在 /var/log/auth.log。在 Rocky Linux 和 AlmaLinux 上,单元名称为 sshd,相同记录也会写入 /var/log/secure。
在 sshd 配置中设置 LogLevel VERBOSE,然后重新加载服务。此后,每次尝试都会记录服务器实际收到的指纹:
Failed publickey for deploy from 198.51.100.7 port 49812 ssh2: ED25519 SHA256:0eL/8sBw...该行可以说明故障位于哪一侧。您识别出的指纹表示密钥已到达服务器,但被服务器拒绝,因此请检查原因 3、4 和 5。您不识别的指纹表示客户端发送了并非您想使用的密钥,因此请返回原因 2。
如果日志仍无法说明问题,请在另一个端口上以调试模式运行第二个 sshd。它会在前台运行,处理一个连接,输出处理过程,然后退出:
sudo /usr/sbin/sshd -ddd -p 2222在同一服务器的控制台会话中,通过回环地址连接到它:
ssh -p 2222 -i ~/.ssh/vps-prod -o IdentitiesOnly=yes deploy@127.0.0.1通过 127.0.0.1 连接可以将防火墙排除在测试之外。调试输出会显示它打开的文件、进行比较的指纹以及确切的拒绝原因,其中包括 Authentication refused: bad ownership or modes for directory /home/deploy 等行。得到答案后按 Ctrl+C。整个过程中,22 端口上的实际 sshd 不受影响。
如何避免将自己锁在服务器之外
每个修改服务器配置的步骤都必须有一种不依赖 SSH 的恢复访问方式。应在 SSH 仍可用时完成设置,不要等 SSH 出现故障后再处理。
- 打开服务商提供的控制台,通过串口或 VNC(虚拟网络计算)连接,并确认可以在其中登录。
- 确认您知道某个具有 sudo 权限的账户的有效本地密码。如果没有,请先通过服务商控制台重置 root 密码。
- 保持当前 SSH 会话处于打开状态。打开的会话可以在
systemctl restart ssh后继续保持,因此新配置错误时,仍可通过该会话恢复访问。 - 重启前检查语法:文件有效时,
sudo sshd -t不输出任何内容;文件无效时,它会输出文件名和行号。 - 打开第二个终端并重新登录,确认成功后再关闭第一个终端。错误的配置会阻止新登录,但不会影响现有会话,因此不能仅凭当前会话判断修改是否生效。
在 Debian 和 Ubuntu 上使用 sudo systemctl restart ssh 重启,在 Rocky Linux 和 AlmaLinux 上使用 sudo systemctl restart sshd 重启。在 Ubuntu 24.04 上,sshd 由 socket unit 启动,因此修改 Port 或 ListenAddress 后,还需要执行 sudo systemctl restart ssh.socket 才会生效。
FAQ
为什么同一个密钥在另一台服务器上可用,在这里却出现 Permission denied (publickey)?
因为密钥本身没有问题,问题出在相关配置或文件上。运行 ssh -v,找到 Offering public key 行。如果其中没有列出您的密钥,说明 ssh 从未发送该密钥:密钥文件不在 ~/.ssh 中的默认文件名下,也没有加载到 agent,因此请添加 -i /path/to/key -o IdentitiesOnly=yes。如果列出了密钥,但服务器仍然拒绝连接,则可能是该密钥不在账户的 authorized_keys 中、相关路径对组可写,或 sshd 配置阻止了该用户。服务器日志可以区分这些情况。
如何查看 SSH 实际发送了哪个密钥?
ssh -v host 会为每个密钥输出一行 debug1: Offering public key:,其中包含源文件和 SHA256 指纹。ssh-add -l 会列出 agent 中保存的指纹。ssh-keygen -lf ~/.ssh/id_ed25519.pub 会输出单个密钥文件的指纹,ssh-keygen -y -f ~/.ssh/id_ed25519 会输出私钥实际派生出的公钥。要使登录成功,Offering 行中的指纹还必须出现在针对服务器的 authorized_keys 执行结果中,即 ssh-keygen -lf 的输出里。
为什么 sshd 会忽略我的 authorized_keys 文件?
因为默认启用了 StrictModes,而文件、.ssh 目录或主目录可能对组或所有用户可写,或者归属错误的账户。sshd 不会信任其他用户可以修改的路径,因此其行为就像不存在任何密钥一样。将主目录权限设置为 755 或更严格,将 .ssh 设置为 700,将 authorized_keys 设置为 600,并确保这三个路径都归登录账户所有。启用 LogLevel VERBOSE 后,服务器会记录 Authentication refused: bad ownership or modes for directory /home/deploy/.ssh。
我的密钥在服务器升级后立即停止工作。发生了什么变化?
如果这是 RSA 密钥,最可能的原因是 SHA-1 相关变更。OpenSSH 8.8 默认禁用了使用 ssh-rsa 的 SHA-1 签名,因此只能以这种方式签名的密钥现在会被拒绝。详细客户端输出会显示 debug1: send_pubkey_test: no mutual signature algorithm。使用 ssh-keygen -t ed25519 生成现代密钥,并安装其 .pub 文件。如果需要立即恢复访问,可在服务器上使用 PubkeyAcceptedAlgorithms +ssh-rsa 重新启用旧签名;新密钥正常工作后,应删除该行。
我编辑了 sshd_config,现在完全无法登录。如何恢复访问?
使用服务提供商的控制台,因为该连接不经过 SSH。在控制台中使用本地密码登录,运行 sudo sshd -t 查看语法错误及其行号,撤销更改,然后重启服务。随后检查 sudo sshd -T 以确认正在运行的配置值,因为 /etc/ssh/sshd_config.d/ 中的文件可能覆盖主配置。如果没有本地密码,先通过控制台重置 root 密码,然后修复该文件。