SSH登录报错Permission denied (publickey)的排查与解决方法(ssh -vvv定位、密钥权限修复与OpenSSH 8.8算法变更)

密钥登录的机器突然连不上,命令行只甩回来一行Permission denied (publickey),换成密码登录却是通的。换过密钥、升过OpenSSH、拷过 .ssh目录之后最容易撞上,而这句报错本身不告诉你是哪一步断了。


从客户端到服务端一共7个检查点,每个都能用一条命令验证,按顺序走就行。


1、先用ssh -vvv看清卡在哪一步

别猜,直接开详细输出:

ssh -vvv -i ~/.ssh/id_ed25519 deploy@10.0.0.7 -p 22

输出里盯三段。出现Offering public key说明客户端确实找到了这把私钥;紧接着是Server accepts key之后又报Permission denied,问题在服务端;连Offering这一行都没有,说明本地压根没加载,用ssh-add -l看agent里有什么。

遇到过另一种情况:agent里塞了七八把钥匙,前面几把先被拒,轮到对的这把时服务端已经达到MaxAuthTries上限直接断开。加 -o IdentitiesOnly=yes让ssh只发指定那把,马上就通。

还有一行很典型:

debug1: send_pubkey_test: no mutual signature algorithm

这句的意思不是密钥错了,是算法谈不拢,看第5步。


2、确认服务端没关掉公钥认证

用密码或者云厂商的控制台登上去,看实际生效的值,而不是配置文件本身:

sshd -T | grep -E 'pubkeyauthentication|permitrootlogin|authorizedkeysfile|strictmodes'

sshd -T打出来的是合并Include之后的结果,/etc/ssh/sshd_config.d/ 下的碎片文件会覆盖主配置里写的东西,只盯着主配置经常白改。改完别急着重启,先跑sshd -t验语法,它会指出哪一行写错了;在没有控制台的云主机上把sshd重启失败,等于把自己关在门外。

要动的三项通常是:

PubkeyAuthentication yes
PubkeyAcceptedAlgorithms +ssh-rsa
AuthorizedKeysFile .ssh/authorized_keys

PubkeyAcceptedAlgorithms是OpenSSH 8.5、8.8、9.6,这一档才有的配置项,写在CentOS 7.9自带的7.4上会导致sshd直接起不来,老系统得用老写法。


3、权限和属主,StrictModes卡得最死

家目录不能被同组或其他人写,.ssh必须是700,authorized_keys必须是600,三者都要属于登录的那个账号。StrictModes默认开着,只要有一条不满足,sshd就当这个文件不存在,连试都不试。

chmod 755 /home/deploy
chmod 700 /home/deploy/.ssh
chmod 600 /home/deploy/.ssh/authorized_keys
chown -R deploy:deploy /home/deploy/.ssh

服务端日志里会留一句Authentication refused: bad ownership or modes for directory /home/deploy/.ssh,见到这句就是权限问题,不用再往别处查。家目录设755就够,设成700反而会让某些需要读家目录的服务跟着出问题。

本地私钥也一样,权限太开放的私钥会被拒绝加载,报UNPROTECTED PRIVATE KEY FILE,改成400或600即可。


4、authorized_keys里的内容对不对

最容易出岔子的两种:一是用编辑器贴公钥时被自动折行,一把钥匙断成两截,前半段就是废内容;二是拷上去的是私钥id_rsa而不是id_rsa.pub。这个文件里必须是ssh-rsa AAAA... 或ssh-ed25519 AAAA... 开头、末尾带注释的完整一行。

验证办法是用私钥反解出公钥,比对指纹:

ssh-keygen -y -f ~/.ssh/id_ed25519 | ssh-keygen -l -f -
ssh-keygen -l -f /home/deploy/.ssh/authorized_keys

两条命令打出的指纹一致才算配对。新加钥匙一律走ssh-copy-id,别手贴:

ssh-copy-id -i ~/.ssh/id_ed25519.pub deploy@10.0.0.7


5、OpenSSH 8.8之后ssh-rsa被默认禁用

2021年发布的OpenSSH 8.8、9.0、9.6,默认关掉了SHA-1的ssh-rsa签名。旧机器上用ssh-keygen默认生成的RSA钥匙,在Ubuntu 22.04、24.04,这类新系统上会被直接拒掉,客户端的详细输出就是前面那句no mutual signature algorithm。见过不少从CentOS 7.9迁到Rocky Linux 9.4的机器在这一步翻车。

三条路,按推荐顺序:

1)重新生成一把ed25519,最干净:

ssh-keygen -t ed25519 -C deploy@node07
ssh-copy-id -i ~/.ssh/id_ed25519.pub deploy@10.0.0.7

2)服务端临时放行,在 /etc/ssh/sshd_config加一行PubkeyAcceptedAlgorithms +ssh-rsa再systemctl restart sshd。这条只用来让旧钥匙顶一阵,等新钥匙铺开就该删掉。

3)客户端侧放行,在 ~/.ssh/config里针对单个主机加,别影响全局:

Host node07
    HostName 10.0.0.7
    User deploy
    IdentityFile ~/.ssh/id_rsa
    PubkeyAcceptedAlgorithms +ssh-rsa
    HostKeyAlgorithms +ssh-rsa


6、用户名、端口、密钥路径

云镜像的默认用户名并不统一,Ubuntu是ubuntu、Amazon Linux是ec2-user、Rocky Linux是rocky、Debian是debian或root,用错用户名同样返回Permission denied (publickey),服务端日志里却只有一条invalid user。实测在同一批机器里,Ubuntu镜像要写ubuntu、Debian镜像要写root,脚本里混用一律被拒,这条在换了发行版之后特别容易被忽略。

另外确认端口,不少机器把sshd挪到了2222之类的端口,客户端没加 -p就会连到根本没开公钥认证的那个服务上。


7、服务端日志给出最终答案

前面都查完还不行,就看服务端为什么拒。systemd系用journalctl -u sshd,RHEL系看 /var/log/secure,Debian系看 /var/log/auth.log。默认日志粒度不够细,把LogLevel提到VERBOSE后重启sshd,认证失败会带上具体原因和钥匙指纹。

journalctl -u sshd -f --since "10 min ago"

Windows上装的OpenSSH Server有两处不一样:配置文件在C:\ProgramData\ssh\sshd_config,管理员账号的公钥要写进 %ProgramData%\ssh\administrators_authorized_keys,而这个文件默认只允许SYSTEM和Administrators访问,用普通编辑器改完ACL会变松,sshd就拒绝加载。修法是先用icacls重置权限,再往里追加。


整套流程走下来,绝大多数Permission denied (publickey) 落在权限、算法、钥匙内容这三处。临时开PubkeyAcceptedAlgorithms +ssh-rsa只是让旧钥匙能撑一阵,正经做法还是换成ed25519一把到位。数据截至2026年9月。