Fix "Host key verification failed." in SSH, Git and scripts

Quick fix

Connect once in a normal terminal, as the same user that runs the failing command, check the fingerprint and answer yes. The key is then stored in ~/.ssh/known_hosts and later non-interactive runs succeed.

# replace with your server or Git host
ssh -T [email protected]
ssh [email protected]
# then re-run the command that failed

The message usually appears on its own, or at the end of a Git or rsync error:

Host key verification failed.
fatal: Could not read from remote repository.

Please make sure you have the correct access rights
and the repository exists.

What the error means

Every SSH server has a host key. On the first connection ssh shows its fingerprint and asks whether to trust it; your answer is saved in ~/.ssh/known_hosts. On later connections ssh compares the server's key with the saved one. "Host key verification failed." means that check did not pass and ssh stopped before authentication, so your login key was never even tried.

Look at what is printed above the error, because it decides which fix you need:

Printed before the errorMeaningGo to
Nothing, or The authenticity of host ... can't be establishedThe key is unknown and ssh could not ask you (no terminal, batch mode)Causes 1 to 3 below
No ED25519 host key is known for ... and you have requested strict checkingKey unknown and StrictHostKeyChecking yes is setCause 4 below
WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!A saved key exists but does not matchREMOTE HOST IDENTIFICATION HAS CHANGED

This page covers the first two rows: the server key is simply not known to the account and context that runs ssh.

Cause 1: a script, Git or CI job runs ssh without a terminal

This is the most common case. The "yes/no" question needs a terminal. Git hooks, IDEs, cron jobs, systemd services, CI runners and ssh -o BatchMode=yes have none, so ssh cannot ask and fails immediately. It works in your terminal only because you answered the question there at some point.

Fix it by adding the key to known_hosts once, after checking it. ssh-keyscan fetches the key, and ssh-keygen -lf shows its fingerprint so you can compare it with the value the server owner or Git host publishes:

ssh-keyscan -t ed25519 github.com > /tmp/gh.key
ssh-keygen -lf /tmp/gh.key
# compare the SHA256 fingerprint with the one the host publishes, then:
mkdir -p -m 700 ~/.ssh
cat /tmp/gh.key >> ~/.ssh/known_hosts

GitHub, GitLab, Bitbucket and Codeberg publish their host key fingerprints in their documentation. For your own servers, read the fingerprint on the server console:

# run on the server
for f in /etc/ssh/ssh_host_*_key.pub; do ssh-keygen -lf "$f"; done
Do not just switch checking off

StrictHostKeyChecking no or UserKnownHostsFile /dev/null in a global config makes ssh trust any server, including an attacker in the middle. A blind ssh-keyscan >> known_hosts without checking the fingerprint is only slightly better (trust on first use).

Cause 2: a different user, so a different known_hosts

known_hosts is per user. You accepted the key as alice, but the failing command runs as someone else:

  • sudo git pull or sudo ssh runs as root and reads /root/.ssh/known_hosts.
  • A web server deploy hook runs as www-data (Debian/Ubuntu) or apache/nginx (Fedora).
  • A systemd service or cron entry runs under a service account, often with a different HOME.

Check which user and file are used by running the same command with -v:

sudo -u deploy ssh -v [email protected] 2>&1 | grep -i known_hosts

Example output:

debug1: load_hostkeys: fopen /home/deploy/.ssh/known_hosts: No such file or directory
debug1: load_hostkeys: fopen /etc/ssh/ssh_known_hosts: No such file or directory

Either accept the key as that user (sudo -u deploy ssh -T [email protected]), or, for keys every account on the machine should trust, add the verified line to the system-wide file /etc/ssh/ssh_known_hosts. Avoid running Git with sudo at all; if you do it to fix ownership errors, see detected dubious ownership instead.

Cause 3: Docker builds and fresh containers

A new container or image has an empty home directory, so git clone git@... inside a Dockerfile or a CI container always fails the first time. Ship a known, checked key with the build instead of scanning at build time:

# known_hosts file you verified once and keep in the repository
COPY known_hosts /root/.ssh/known_hosts
RUN chmod 700 /root/.ssh && chmod 644 /root/.ssh/known_hosts

Most CI systems (GitHub Actions, GitLab CI, Jenkins) let you store the known_hosts content as a variable or secret and write it to ~/.ssh/known_hosts in the job. That keeps the protection and survives runner rebuilds. For Docker itself see Docker on Linux.

Cause 4: StrictHostKeyChecking yes, and other name mismatches

If your ~/.ssh/config, /etc/ssh/ssh_config or a file in /etc/ssh/ssh_config.d/ sets StrictHostKeyChecking yes, ssh never adds keys automatically, even in a terminal. That is a sound setting for servers; add the key with the method from cause 1.

The saved entry must also match the name you connect with. Entries are stored per host name, per IP and per port, so these are three different hosts to ssh:

ssh server.example.com
ssh 203.0.113.10
ssh -p 2222 server.example.com     # stored as [server.example.com]:2222

Check whether an entry exists for exactly the name you use (works with hashed files too):

ssh-keygen -F server.example.com
ssh-keygen -F '[server.example.com]:2222'

For automation where the host list changes and keys cannot be pre-distributed, a per-host accept-new is a reasonable compromise: it saves unknown keys but still refuses changed ones.

Host build-*.internal.example.com
    StrictHostKeyChecking accept-new

Tool-specific notes

  • Git: Git calls ssh, so every fix above applies. GIT_SSH_COMMAND="ssh -v" git fetch shows the ssh debug output. See Git on Linux for setup.
  • Ansible: it uses the controller user's known_hosts. Keep host_key_checking enabled and pre-populate known_hosts (for example with the known_hosts module) rather than disabling it in ansible.cfg.
  • rsync, scp, sftp: same mechanism; test with ssh user@host first, as the user that runs the job.
  • VS Code Remote-SSH: it uses your normal ~/.ssh/known_hosts; connecting once in a terminal fixes it.

Distro notes

The client is OpenSSH on all major distributions, so the behaviour is the same on Ubuntu, Debian and Mint (openssh-client), Fedora (openssh-clients), Arch (openssh) and openSUSE (openssh-clients). Debian and Ubuntu set HashKnownHosts yes in /etc/ssh/ssh_config, so known_hosts entries look like |1|... and you cannot grep for host names; use ssh-keygen -F host and ssh-keygen -R host instead. Fedora, Arch and openSUSE store plain host names by default.

On Fedora and openSUSE Leap 16 with SELinux enforcing, a known_hosts file created by root for another account can carry the wrong label; restorecon -Rv ~/.ssh fixes it.

How to prevent it

  • Keep a verified known_hosts file for your Git hosts and servers and deploy it with your configuration management or CI secrets.
  • Run deploy and backup jobs as one dedicated user and accept keys as that user.
  • Use Host blocks in ~/.ssh/config so you always connect with the same name and port; the SSH cheat sheet lists the options.
  • Never put StrictHostKeyChecking no in a global config. Use accept-new on specific hosts only.

Once the host key is accepted, the next possible failure is authentication itself: see Permission denied (publickey) and setting up SSH keys.

Frequently asked questions

How do I fix Host key verification failed with git clone?

Connect once interactively with ssh -T [email protected] (or your Git host), compare the fingerprint with the one the host publishes, and type yes. The key is saved to ~/.ssh/known_hosts and git works afterwards.

Is it safe to set StrictHostKeyChecking no?

No. It makes ssh accept any key, including an attacker's, so it removes the protection against man-in-the-middle attacks. Use StrictHostKeyChecking accept-new for a specific host if you must automate first contact, or better, pre-load verified keys.

Why does it work as my user but fail with sudo?

With sudo, ssh runs as root and reads /root/.ssh/known_hosts, which does not contain the key you accepted as your user. Run git or ssh without sudo, or add the key to root's file or to /etc/ssh/ssh_known_hosts.

What is the difference from REMOTE HOST IDENTIFICATION HAS CHANGED?

If that big warning appears above the error, the saved key no longer matches the server, which needs a different fix. If you only see Host key verification failed, the key is usually missing from known_hosts and ssh could not ask you to accept it.

Spotted a mistake or a command that no longer works? Send a correction — pages are re-checked when reports come in.