资讯动态

GitHub SSH Permission denied (publickey) 排查指南

发布时间:2026/9/13 4:24:03 来源:尧图企业网站定制
大概每个用Git的开发者都碰到过这行红字gitgithub.com: Permission denied (publickey). fatal: 无法读取远程仓库。 请确认您有正确的访问权限并且仓库存在。我第一次遇到的时候第一反应是去检查仓库地址有没有写错反反复复看了好几遍发现地址根本没问题。然后我又怀疑是不是GitHub服务器出故障了跑去各种网站查状态折腾了快一个小时才意识到问题压根不在仓库存不存在而是我的电脑根本没通过GitHub的SSH身份验证。这篇文章我就把自己踩过的坑和完整的排查思路整理出来。不管你是刚接触Git的新手还是被这个问题反复折磨过的老手照着下面的顺序一步步来基本都能定位到原因。1. 这个报错到底在说什么先把SSH公钥认证的完整链条捋清楚很多人在第一步就搞错了方向因为被报错里的无法读取远程仓库带偏了。其实这句话只是一个结果真正的根因在它前面那句Permission denied (publickey)。1.1 拆解报错文字里的两个关键信息Permission denied (publickey)是SSH层面的错误而fatal: 无法读取远程仓库是Git层面的错误。两者的关系是层层递进的SSH认证失败Git自然就没法继续读取仓库。关键在于publickey这个词。它表示GitHub服务器在回应这次连接请求时明确说我只接受公钥认证方式但是你没有提供能通过验证的公钥。注意这里有个非常容易混淆的点。如果你看到的报错是Permission denied (password)或者Permission denied (keyboard-interactive)那走的是密码认证场景完全不同。而publickey就是纯粹的公钥认证失败。还有一个更反直觉的事这个报错不代表你的电脑连不上GitHub服务器。相反你的电脑已经成功连接到GitHub的SSH端口只是在认证这一步被拦住了。这就好比你能走到公司门口但门禁卡刷不进去和公司倒闭搬走了是两码事。1.2 公钥认证的完整原理门卫、登记表和门禁卡要理解这个报错得先搞清楚SSH公钥认证是怎么工作的。整个过程可以类比成进公司大门你的电脑上保存着一把私钥对应你身上的门禁卡。这把钥匙永远只留在你自己的电脑上。GitHub服务器上保存着一把公钥对应门卫手里的登记表。公钥是从私钥推导出来的可以公开给任何人。当你发起连接时服务器会发送一个随机的挑战数据给你的电脑。你的电脑用私钥对这个挑战签名然后把签名结果发回去。服务器用登记表里的公钥去验证这个签名。如果验证通过说明你确实持有与公钥配对的私钥于是放行如果验证失败就回复Permission denied。你发现了没有私钥和公钥严格配对公钥验证通过的前提是服务器上已经存了对应的公钥。任何一个环节脱节比如电脑上根本没有私钥或者GitHub上根本没登记公钥或者登记的是一对不匹配的密钥都会出现publickey报错。1.3 先弄清你的连接到底用的是SSH还是HTTPS还有一个前提问题值得先确认。Git连接远程仓库有两种常见协议SSH和HTTPS。SSH地址长这样gitgithub.com:用户名/仓库名.gitHTTPS地址长这样https://github.com/用户名/仓库名.git只有用了SSH地址才会触发公钥认证机制。如果你用的是HTTPS地址报错形式通常不一样比如提示输入用户名密码或者提示could not read Username for https://github.com。可以用git remote -v看看自己当前仓库的远程地址长成gitgithub.com:...的才是走SSH通道。2. 第一步排查用一条指令把连不上和没权限分清楚收到publickey报错后我建议你先别急着重新生成密钥也别急着看GitHub后台。先做一次干净利落的连通性测试确定问题到底属于哪一大类。2.1 用ssh -T命令直接测试认证终端里执行这条命令ssh -T gitgithub.comGitHub的SSH服务有个特点不管认证成不成功它都会关闭Shell访问所以你不用指望它能给你一个交互式Shell。关键在于看它的回复内容。如果是认证成功你会看到类似这样的输出Hi yourusername! Youve successfully authenticated, but GitHub does not provide shell access.注意这里会带上你的GitHub用户名。能看到这行说明你的SSH公钥已经通过了GitHub的认证问题根本不在SSH钥匙上。这种情况下你该检查的是Git仓库本身、分支的远程跟踪关系、分支保护规则之类的Git层面问题。如果你看到的还是可怕的Permission denied (publickey)那说明SSH认证这关确实没过继续往下看。还有一种容易被忽略的情况输出是kex_exchange_identification、Connection timed out、Could not resolve hostname这类信息。这说明压根没连上GitHub服务器属于网络连通性问题和公钥认证完全是两条路线。需要先解决网络问题再回来检查密钥。2.2 用verbose模式看SSH到底做了什么如果确认是认证失败加一个-v参数重新执行能拿到更详细的过程日志ssh -Tv gitgithub.com输出会很长建议重点看末尾部分的几行关键信息。我截一段典型的失败日志debug1: Offering public key: /home/user/.ssh/id_rsa RSA SHA256:xxxxxx debug1: Authentications that can continue: publickey debug1: Trying private key: /home/user/.ssh/id_ed25519 debug1: Authentications that can continue: publickey debug1: No more authentication methods to try. gitgithub.com: Permission denied (publickey).这里透露了两个信息Offering public key后面的路径表示SSH客户端尝试用的是哪个私钥文件。Authentications that can continue: publickey表示服务器只接受公钥认证不接受密码。如果这些信息对不上号比如你明明把新公钥给了GitHub但SSH固执地拿着旧的私钥去试那问题就出在客户端选错了钥匙上后面第4章会详细讲多账号场景。2.3 为什么我反复强调先做这一步直接去生成新密钥当然也行大多数情况下能解决问题。但我还是建议先跑一下ssh -T理由很简单它能避免你白忙一场。我见过有人在自己的电脑上生成了新密钥也干净利落地配置好了最后发现一无是处因为他的问题其实是公司内网的认证网关挡住了SSH端口。这就是典型的方向错了做工白费。另外这一步还能帮你确认现状以前能用但突然不能用和一开始就不能用排查方向是完全不同的。前者优先考虑密钥被动过后者优先考虑从来就没配置完整过。先跑条命令用日志作为决策依据。3. 八成问题出在对不上账本地密钥、ssh-agent和GitHub后台的三角关系如果确认是publickey认证失败那绝大多数情况就是对不上账——你电脑上有的私钥在GitHub后台找不到对应的公钥或者反过来GitHub后台有什么但你电脑上压根没这个私钥。下面按顺序过一遍。3.1 检查本地是否存在密钥文件你先看看~/.ssh目录里有什么ls -la ~/.ssh/常见默认密钥文件名有两个id_rsa和id_rsa.pub老牌RSA密钥id_ed25519和id_ed25519.pub现代推荐使用的Ed25519密钥~表示当前用户的主目录。在Linux和macOS下就是/home/用户名或/Users/用户名在Windows的Git Bash下通常指向C:\Users\你的用户名。如果这个目录压根不存在或者里面空荡荡那答案很明确了你从来没生成过SSH密钥。有些Git客户端在安装时会自动帮你生成一套但如果你用的是一台新的电脑或者刚刚重装了系统密钥文件很可能就是没有的。3.2 生成一对新密钥并加入ssh-agent确认没有密钥后生成一对新的。现在推荐用Ed25519ssh-keygen -t ed25519 -C 你的邮箱或自定义注释-C后面的内容只是注释用来标记这个密钥是谁的不影响功能。建议填个容易识别的信息比如你的GitHub用户名或者邮箱。之后系统会问你保存路径和passphrase保存路径直接回车用默认的~/.ssh/id_ed25519。passphrase可以留空也可以设置。留空最方便但如果你的电脑有被他人接触的风险建议设置一个。设置后每次用私钥都要输一遍密码这时ssh-agent就派上用场了。生成后启动ssh-agent并把密钥加载进去eval $(ssh-agent -s) ssh-add ~/.ssh/id_ed25519如果你给密钥设置了passphrasessh-add时会让你输入一次。之后在会话内使用密钥就不会反复要密码了。macOS用户在执行ssh-add时可以加一个--apple-use-keychain参数把passphrase放进系统的钥匙串里重启后也不用重新输入。3.3 把公钥内容粘贴到GitHub后台生成密钥后用下面命令查看公钥内容cat ~/.ssh/id_ed25519.pub会输出以ssh-ed25519开头的一长串字符。复制它。然后打开GitHub网页端进入Settings→SSH and GPG keys点击New SSH keyTitle随便填比如我的笔记本、公司台式机方便以后区分。Key type保持Authentication Key。Key里粘贴刚才复制的公钥内容。粘贴时注意别漏字符。公钥是一整行结尾通常有邮箱或注释如果复制时换行被破坏可能会导致公钥失效。3.4 重新验证配置完成后再跑一次ssh -T gitgithub.com看到Hi username! Youve successfully authenticated就说明SSH通道通了。这时候再git push应该能正常推上去。3.5 为什么有时生成了密钥、也加到了GitHub还是报错这种情况真不少见。我总结了一下通常是这几个原因造成的第一个原因是ssh-agent里没有这个密钥。你生成了密钥文件GitHub后台也加了公钥但SSH客户端连私钥文件都没加载到agent里。运行ssh-add -l看看有没有列出私钥没有的话用前面说的ssh-add ~/.ssh/id_ed25519加进去。第二个原因是系统里存在多个密钥文件SSH客户端按顺序尝试但优先试的那把钥匙不对应GitHub后台的任何公钥。要确认是不是这种情况可以看ssh -Tv日志里的Offering public key是哪把钥匙。第三个原因比较隐蔽你把公钥文件内容复制错了。比如复制成了私钥id_ed25519而不是id_ed25519.pub或者复制时中间少了换行。GitHub后台对格式很挑剔冒然贴错会导致无法识别。4. 多账号才是坑王为什么你有密钥却依然被拒绝解决了基本配置如果你还是碰到publickey报错并且你已经确认密钥存在、GitHub后台也有公钥那下一个重点怀疑对象就是多账号冲突。4.1 典型的冤案现场想象一个很常见的场景你的电脑上先配置了GitLab的公司账号生成了~/.ssh/id_rsa和~/.ssh/id_rsa.pub这个密钥一直在正常使用。某一天你想推GitHub的代码又生成了一套新密钥~/.ssh/id_ed25519_github并把公钥添加到了GitHub。你觉得自己配置得没问题结果git push还是被拒。为什么因为SSH客户端默认会拿id_rsa去连接GitHub。而GitHub后台没有这把公钥于是认证失败。虽然你有一把能通过认证的id_ed25519_github但SSH客户端出于默认顺序可能压根没试到它或者试的时候已经被前面的失败影响了。4.2 用~/.ssh/config文件管理多把密钥解决办法是建立一个~/.ssh/config文件让SSH客户端根据连接的Host自动选择正确的私钥。Host github.com HostName github.com User git IdentityFile ~/.ssh/id_ed25519_github IdentitiesOnly yes Host gitlab.company.com HostName gitlab.company.com User git IdentityFile ~/.ssh/id_rsa IdentitiesOnly yes这里最要紧的是IdentitiesOnly yes这一行。它告诉SSH客户端连接这个Host时只用IdentityFile指定的密钥不要自作主张把agent里所有密钥都试一遍。不加这行在某些配置下SSH会优先尝试默认密钥导致你指定的密钥根本没机会上场。4.3 修改remote地址配合config的别名如果你在config里给Host取了别名比如Host github-personal HostName github.com User git IdentityFile ~/.ssh/id_ed25519_github那么git clone或切换remote时地址里的github.com要改成github-personalgit remote set-url origin gitgithub-personal:你的用户名/仓库名.git很多人改了config却忘了改remote地址里的Host结果还是用默认值去连自然还是失败。这个细节特别容易漏。4.4 同一个公钥不要加到多个GitHub账号GitHub规定同一个公钥只能归属于一个用户账号。如果你把同一把公钥同时添加到了账号A和账号BGitHub通常会拒绝在第二个账号上添加或者直接导致认证信息错乱。这个约束意味着如果你有两个GitHub账号每个账号都要用不同的密钥。这也是config文件多Host配置的典型用途。4.5 企业GitHub和私有化部署的差异如果你用是公司内部部署的GitHub Enterprise连接地址可能不是github.com而是git.company.com之类的域名。这时候ssh -T gitgithub.com针对的是GitHub官方服务器测出来的结果并不能代表你真正要连的目标。排查时一定要确认你实际连接的Host到底是哪个别拿着公共GitHub的测试结果去判断企业内部服务器的问题。5. 那些容易被忽略的边缘案发现场known_hosts、密钥权限和仓库地址密钥对得上、SSH配置也没问题却依然报publickey的场景我遇到过不少。这类问题往往藏在一些容易被忽略的细节里。5.1 known_hosts里的坏记录会导致链接被重置~/.ssh/known_hosts文件记录了你曾连接过的服务器指纹。正常情况下它是安全的但如果你之前用错误的公钥连接过GitHub或者系统时间大幅跳动导致host key校验异常known_hosts里的记录就可能和实际情况对不上。虽然这通常报的是Host key verification failed和publickey字面上不同但某些情况下它会在认证阶段之前就中断连接表现出来的现象和认证失败非常相似。遇到可疑情况先清掉github.com的历史记录ssh-keygen -R github.com然后再重新连接这次会提示你是否接受新的host key输入yes即可。5.2 私钥文件的权限太开放SSH会拒绝使用OpenSSH有一个安全策略如果私钥文件的权限太宽松比如其他人也能读它宁可拒绝使用这个密钥也不会冒险加载。你在终端可能会看到这样的提示Permissions 0644 for /home/user/.ssh/id_ed25519 are too open.修复方式很简单chmod 600 ~/.ssh/id_ed25519 chmod 700 ~/.ssh注意目录权限和文件权限都要处理。~/.ssh目录如果不是只有你一个人能访问保持700权限是最稳妥的。Windows系统上OpenSSH对权限的检查逻辑略有不同但思路一样确保私钥文件不要被Everyone或Users组读取。5.3 remote地址写错尤其是把SSH和HTTPS混着写有人会把remote地址写成这样gitgithub.com:用户名/仓库名.git ← 正确的SSH格式但在某些复制粘贴过程中可能变成gitgithub.com/用户名/仓库名.git ← 少了冒号的错误写法一个符号的差异导致SSH客户端解析地址的方式不同最终连接失败。另外GitHub的SSH连接用户固定是git你不能把它改成自己的用户名。如果有人把地址写成了yourusernamegithub.com:...照样会报错。用下面命令检查当前仓库的remote地址git remote -v正确的SSH格式一定是gitgithub.com:作为前缀中间是冒号而不是斜杠。5.4 GitHub后台的密钥真的还在吗有时候你以为自己在GitHub后台配置了公钥实际上那个key可能已经被删除或失效了。比如公司的IT安全策略定期清理SSH key或者你在GitHub网页上误操作删除了又或者GitHub账号因为安全风控被临时冻结了key的使用权限。这种情况的特征是以前能正常推送某一天突然开始报publickey错误。排查方式是重新登录GitHub后台在Settings→SSH and GPG keys页面检查要用的公钥是否还在。不在了就重新添加一次顺便核对公钥内容和本地.pub文件是否一致。5.5 Windows环境下的特殊坑Windows用户有些额外问题需要注意。第一Git Bash和PowerShell里ssh命令可能指向不同的OpenSSH实现。运行which ssh看看具体用的是哪个版本不同版本的配置读取逻辑可能有细微差别。第二~路径解析。Git Bash里的~通常指向C:\Users\你的用户名但如果你的进程是以管理员或者其他用户身份运行的指向的位置就变了。密钥文件明明在用户A的目录下但SSH客户端以用户B的身份运行时读不到一样报publickey。第三Git for Windows自带了一套SSHWindows系统也有一套OpenSSH。如果两边版本差异过大配置文件的解析方式可能不一致。可以通过git config --global core.ssh ssh强制Git使用系统的OpenSSH客户端或者用git config --global core.ssh C:/Program Files/Git/usr/bin/ssh.exe强制使用Git自带的。5.6 临时应急方案改用HTTPS协议如果被这个问题卡得死死但代码又急着推可以将remote地址暂时切换为HTTPS协议git remote set-url origin https://github.com/用户名/仓库名.git推送的时候GitHub已经不支持用账号密码直接推送了需要你用用户名加一个Personal Access TokenPAT。PAT需要在GitHub后台生成权限范围选择repo即可。HTTPS方式推送时如果你不想每次输密码可以启用Git的凭据管理器git config --global credential.helper store或者用manager模式它会把凭据存到系统钥匙串里。但我要说的是这只能当应急方案。HTTPS方式在频繁推送时每次都走账号密码流程体验不如SSH顺滑。而且PAT如果泄露账号安全风险很大。所以问题解决后建议还是切回SSH。切换回来后记得重新设置remote地址。6. 一套完整的排查顺序照着做就行最后我把整个排查流程串成一份可执行的清单。我自己的经验是按顺序从头到尾过一遍不要跳步15分钟内基本能找出问题。6.1 快速排查检查清单第一步确认网络连通性。ssh -T gitgithub.com如果输出Permission denied (publickey)继续往下走如果是超时、拒绝连接、无法解析域名先解决网络问题。第二步查看本地密钥文件。ls -la ~/.ssh/确认id_ed25519或id_rsa等密钥文件存在。不存在就生成新密钥。第三步检查ssh-agent里加载了哪些密钥。ssh-add -l如果显示The agent has no identities.说明没有加载任何密钥用ssh-add ~/.ssh/id_ed25519加载。第四步核对GitHub后台公钥。登录GitHubSettings→SSH and GPG keys确认你本地的id_ed25519.pub内容与之完全一致。第五步检查多账号配置。如果有多个密钥文件或多账号需求查看~/.ssh/config确认连接github.com时用了正确的IdentityFile并且有IdentitiesOnly yes。第六步检查权限位主要是Linux/macOS。chmod 600 ~/.ssh/id_ed25519 chmod 700 ~/.ssh第七步再跑一次验证。ssh -T gitgithub.com看到Hi username!就说明认证通过了。这个时候回Git仓库重新推送即可。6.2 一个一句话排查法如果不想记那么多细节就记住这一条让ssh -T gitgithub.com跑通Git推送基本就顺了。这句话听起来像是废话但确实是我几年下来最深的体会。Git推送报publickey的根子十个里有八个是SSH认证通道没打通而ssh -T就是这条通道的探针。6.3 我在实际配置中的两点个人体会第一点是新电脑第一次配置GitHub时一定要按生成密钥 → 加载agent → 粘贴公钥 → 验证这个顺序走一遍不要跳跃。我见过有人在公司电脑上用sudo生成了密钥结果密钥路径在/root/.ssh下普通用户根本读不到排查了很久才发现路径不对。第二点是每次重装系统或者换电脑最容易忘的就是把新公钥加到GitHub。旧电脑的密钥虽然还留在GitHub后台但新电脑没有对应的私钥等于钥匙在家里没锁在门锁上自然推不动。及时清理后台废弃的公钥也能避免以后混淆。如果你正好把报错字面信息和GitHub后台配置反复核对了几遍都没发现异常建议再花两分钟试试第5章提到的known_hosts清理、密钥权限修正、remote地址检查这些边缘操作。SSH这套机制本身是稳定的出问题基本就是我们哪一步配置的细节没做对。按顺序排查不要慌基本都能解决。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价