git 认证失败 Authentication failed 速查:密码、token 与 SSH key
更新时间:2026-10-24。FAQ 速查页,面向 push/pull 私有仓库时被
fatal: Authentication failed或Permission denied (publickey)挡住的同学。这类报错的特点是:网络通、仓库也在,就是「服务端不认你」。收敛在六根轴上:平台已弃用密码只收 token、token 权限或有效期不够、credential helper 里存着旧凭据顶在前面、SSH key 没生成或没加进 agent、多账号场景选错 key、以及 remote URL 的协议和你配的凭据不匹配(拿 SSH 的 key 去走 HTTPS)。顺一遍基本必中。
本文要回答的问题
Authentication failed for 'https://...'与Permission denied (publickey)分别对应哪条认证链?- 密码明明是对的,为什么平台还是拒绝?
- 改过密码/token 后还是失败,谁在偷偷用旧凭据?
ssh -T git@git.example.com这条命令怎么读?- 一台机器上两个账号(公司+个人)怎么不串号?
一、报错原文与典型现象
HTTPS 与 SSH 两条链路的报错原文长得完全不同(主机名以 git.example.com 占位,路径以 /proj/demo 占位):
$ git -C /proj/demo push origin master
Username for 'https://git.example.com': zhangsan
Password for 'https://zhangsan@git.example.com':
remote: 密码口令认证已被平台移除,请改用 personal access token(原报错为英文提示)。
fatal: Authentication failed for 'https://git.example.com/zhangsan/demo.git/'$ git -C /proj/demo push origin master
git@git.example.com: Permission denied (publickey).
fatal: Could not read from remote repository.
Please make sure you have the correct access rights
and the repository exists.读报错先分协议:报文里带 https:// 的是 token/凭据链,带 git@ 的是 SSH key 链,两条链的凭据体系完全独立,修错边是新人最常见的空转。第二看 remote 的附言——平台附言会直接点破「密码认证已移除」这类病因,别忽略。
二、病因处置速查表
| 报错现象 / 场景 | 可能原因 | 快速验证 | 处置 |
|---|---|---|---|
| HTTPS 输密码必失败 | 平台已弃用密码认证 | remote 附言提示 use a personal access token | 后台生成 token,密码处粘贴 token |
| token 也失败 | token 过期或没勾 repo/write 权限 | 平台后台看 token 的 Expiration 与 Scopes | 重建 token 并勾足权限,更新本机凭据 |
| 改了密码仍失败 | credential helper 缓存旧凭据顶在前面 | git credential fill 看吐出来的是不是旧的 | 清除旧条目(见正文命令)后重试 |
| SSH 报 Permission denied | 公钥没上传到平台,或 key 根本没生成 | ssh -T git@git.example.com;ls ~/.ssh/id_*.pub | 生成 key、上传公钥、重测 ssh -T |
| 本机有 key 但仍 publickey | key 未加入 ssh-agent 或 agent 没起 | ssh-add -l 为空 | eval $(ssh-agent) + ssh-add ~/.ssh/id_ed25519 |
| 多账号机器时而通时而不通 | 默认 key 被发给错的账号 | ssh -T 回显的 Hi 后面是谁 | ~/.ssh/config 按 Host 别名分 key |
| 以前好好的,换了 remote 地址后失败 | HTTPS/SSH 协议与凭据不匹配 | git remote -v 看是 https 还是 git@ | 协议二选一,凭据按所选协议配齐 |
三、排查决策图
下面这张图是标准排查路线,颜色按角色区分:红是报错入口与命中的根因,蓝是排查动作,绿是通过分支,橙是修复动作,紫是防复发沉淀。
读这张图抓一个分水岭:git remote -v 先把协议切开,之后两条支路互不相干——HTTPS 链的全部动作围绕 token 与本机凭据缓存,SSH 链的全部动作围绕密钥对与 agent。哪边都不通时先怀疑自己看错了 remote 地址(比如公司代理只放行 443,22 端口被墙时 SSH 链天生不通),再逐层往下修。
四、逐条排查展开
第一条:密码已死,token 当立。 GitHub 在 2021 年 8 月就关掉了 Git 操作的密码认证,GitLab、Gitee 等平台也陆续跟上。在 Password 提示符下输登录密码,服务端必然回 Authentication failed,而且很多平台会附一行「密码认证已被移除,请改用 personal access token」的英文提示。修法是到平台后台(Settings → Developer settings → Personal access tokens)生成一个 token,下次提示 Password 时把 token 粘进去。token 只显示一次,当场记好。
第二条:token 权限与有效期。 fine-grained token 默认权限很窄,只勾了 Contents: Read 的 token 推送时照样失败;classic token 至少要勾 repo。另外 token 有过期日,某天突然全部失败先去后台看 Expiration。确认动作是拿 token 直接测 API 或 git ls-remote,排除「其实 token 是对的、错在别处」。
第三条:credential helper 的旧凭据。 这是「我明明改了密码怎么还不行」的标准答案:macOS 的 osxkeychain、Windows 的 manager、Linux 的 store/cache,都会把第一次输对的凭据存下来自动提交,你换 token 后它还在顶旧的。处置:
# 看 git 实际会提交什么凭据
printf "protocol=https\nhost=git.example.com\n" | git credential fill
# 删掉旧条目,让它下次重新问
printf "protocol=https\nhost=git.example.com" | git credential erasemacOS 上也可直接开「钥匙串访问」搜 git.example.com 删掉对应条目;Windows 在「凭据管理器 → Windows 凭据」里删。删完再 push 会重新提示输入,这次填新 token。
第四条:SSH 链三件套:key、上传、agent。 Permission denied (publickey) 的意思是服务端用你提供的公钥一个都对不上。逐层确认:
ls ~/.ssh/id_ed25519.pub ~/.ssh/id_rsa.pub 2>/dev/null # 有没有 key
cat ~/.ssh/id_ed25519.pub # 这串要上传平台
ssh-add -l # agent 里挂着谁
ssh -T git@git.example.com # 端到端验证没有 key 就 ssh-keygen -t ed25519 -C "you@example.com";有 key 没上传就把 .pub 全文粘到平台 SSH Keys 页;ssh-add -l 为空就 ssh-add ~/.ssh/id_ed25519。ssh -T 回显 Hi zhangsan! You've successfully authenticated 才算通,同时核对回显的账号名是不是你以为的那个。
第五条:多账号的 key 选择。 一台机器挂着公司号和个人号时,SSH 默认按顺序试 key,第一个被服务端接受的就赢——常常把个人 key 发给公司仓库,于是 publickey。解法是在 ~/.ssh/config 里按 Host 别名绑死:
Host git-work
HostName git.example.com
IdentityFile ~/.ssh/id_ed25519_work
IdentitiesOnly yesremote 地址写成 git-work:org/repo.git,IdentitiesOnly yes 保证不拿别的 key 去碰运气。配完用 ssh -T git-work 验证,回显的账号名应当变成公司号;不变说明 config 没生效,检查文件路径是不是 ~/.ssh/config、有没有拼错 Host 名。
第六条:协议与凭据错配。 git remote -v 看一眼:地址是 https:// 开头的,SSH key 配得再好也用不上;是 git@ 开头的,token 同理。换协议一条命令:git remote set-url origin git@git.example.com:zhangsan/demo.git。协议选择与 push/pull 的完整口径见 remote、pull、push 用法。此外企业内网常封 22 端口,SSH 死活不通时改走 HTTPS 或平台提供的 443 端口 SSH 别名即可。
第七条:双因素认证(2FA)开了以后,密码彻底失效。 平台强制 2FA 的账号,HTTPS 的 Git 操作只认 token,SSH 链不受影响。如果某天 HTTPS 突然全挂而 SSH 正常,回想一下是不是刚按平台要求开了 2FA——这不算故障,是认证规则变了,把 HTTPS 链迁到 token 即可。
第八条:代理与公司网络的伪装失败。 走 HTTP 代理时,代理自身的 407 认证失败有时会被 Git 的报错包装得让人误以为是 Git 服务端拒绝;企业网关拦 SSH 的 22 端口时,报错是 Connection timed out 或 Connection refused,与 publickey 无关。区分办法:看报错的措辞里有没有 Authenticated 字样,以及 curl -v https://git.example.com 能不能通到 TLS 层。网络层的拒绝请转网络排查,别在凭据上空转。
第九条:CI/CD 里的认证是另一套体系。 流水线里报 Authentication failed,基本不是密码问题,而是 CI 用的 deploy key / access token 过期、权限收窄、或 secret 变量改名后脚本还在引用旧变量。CI 环境没有交互提示符,凭据全靠注入,排查起点是 CI 的变量设置页而不是本机钥匙串。还有一个隐蔽点:CI 镜像里预装的 git 版本过旧时,对新版凭据助手协议支持不全,症状是凭据明明注入了却仍然失败,升级基础镜像里的 git 即解。
五、规范做法与预防
- token 入库登记:生成时记下用途、权限、到期日,到期前一周换,别等全线报错。
- 一台机器一套 ssh config:多账号一律 Host 别名 + IdentitiesOnly,不靠默认顺序碰运气。
- 换凭据后先 erase 再试:形成肌肉记忆,省掉「旧凭据顶包」这一轮空转。
- ssh -T 当体检:新机器、新 key、新账号的第一动作都是
ssh -T,回显账号名对了再干活。 - 凭据绝不进脚本/仓库:token 写进代码或 CI 日志等于泄露,CI 用平台的密钥变量注入;一旦疑似泄露,第一件事是去平台后台吊销,不是改代码。
- 私钥加密码短语:
ssh-keygen时设 passphrase、配合 agent 缓存,机器丢了私钥也不等于仓库大门敞开。 - 协议选一套用到底:一个仓库的 remote 协议和本机凭据方案要成对出现,团队 README 里写明推荐协议,新人少走弯路。
这一篇在知识体系里的位置
本篇是 Git 排错速查簇的认证篇,定位「服务端不认你」:连仓库都找不到(not a git repository)看 not a git repository 报错速查;认证通过但推送被拒(non-fast-forward)看 Git push 被拒 non-fast-forward 速查;HTTPS/SSH 协议选择与日常推拉看 remote、pull、push 用法;建仓与初始配置看 Git 配置、init 与 clone;user.name/user.email 身份配置(与认证是两回事)同样见配置篇。
一句话总结
git 认证失败先 git remote -v 分协议:HTTPS 链报 Authentication failed,九成是平台弃用密码要换 token、token 权限/到期不够、或 credential helper 存着旧凭据(git credential erase 清掉重输);SSH 链报 Permission denied (publickey),按「ls ~/.ssh 有 key → 公钥已上传 → ssh-add -l 已挂 → ssh -T git@git.example.com 回显正确账号」四步走,多账号用 ~/.ssh/config 的 Host 别名加 IdentitiesOnly 绑死。token 记到期日、凭据不进脚本,这类报错基本绝迹。