What is known_hosts, and how do you verify an SSH host fingerprint?

~/.ssh/known_hosts lists the public host keys of servers you have connected to, so ssh can tell if a server later presents a different one. To verify a fingerprint, run ssh-keygen -lf /etc/ssh/ssh_host_ed25519_key.pub on the server through a trusted channel, such as a console, and compare it with what ssh shows.

Updated . ssh-keygen -F, -R, -H and -lf, ssh-keyscan, StrictHostKeyChecking values and UpdateHostKeys=yes were run with OpenSSH 10.3 on macOS against OpenSSH 10.0 on Debian 13, with temporary known_hosts files.

What it is for

An SSH client needs to know it is talking to the real server before it sends a password or runs a command. On first connection it shows the server's fingerprint and asks. If you accept, the public key goes in known_hosts. On later connections the check is automatic, and a different key gives the REMOTE HOST IDENTIFICATION HAS CHANGED error.

The file holds only public keys. It contains no secrets, but it does reveal which servers you use.

The format

203.0.113.10 ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGYt...
[server]:2222 ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMJi...
server,203.0.113.10 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAB...

Each line has the host names, the key type and the key. A port other than 22 is written in brackets, as [server]:2222. Names can be a comma separated list, and may include wildcards. Two optional markers can come first: @cert-authority for a CA key, and @revoked for a key that must never be accepted. With SSH host certificates, one CA line can replace a line for every server.

The client also reads a system-wide file, /etc/ssh/ssh_known_hosts, which an administrator can fill in for everyone.

Hashed entries

|1|eoQ3SZFlQ/5gRWuuw3MoS+AtytA=|BlzFc5MrVrt8iIEm7rloTmKPRBo= ssh-ed25519 AAAAC3Nz...

A line starting with |1| has the host name hashed, so anyone who steals the file does not get a ready list of your servers. ssh still finds it. It is controlled by HashKnownHosts. The OpenSSH default is no, but Debian turns it on in /etc/ssh/ssh_config, so you will see both forms.

To hash an existing file:

ssh-keygen -H

This keeps the original as known_hosts.old, in plain text. Delete that copy if privacy is why you did it.

Everyday commands

These work on hashed files too. Add -f file to use a file other than the default.

GoalCommand
Find a host's entryssh-keygen -F server
Find one on another portssh-keygen -F '[server]:2222'
Show that host's fingerprintssh-keygen -lF server
List all fingerprintsssh-keygen -lf ~/.ssh/known_hosts
Remove a hostssh-keygen -R server

With -F, the exit code is 1 if the host is not found, which is useful in scripts. -R exits 0 either way.

How to verify a fingerprint

On first connection you see this:

The authenticity of host 'server (203.0.113.10)' can't be established.
ED25519 key fingerprint is: SHA256:iU7+QOFWSHJeCFBdzU31dTOoJRNhncp+Wzw3UJMzasU
This key is not known by any other names.
Are you sure you want to continue connecting (yes/no/[fingerprint])?

Typing yes without checking means trusting whatever answered. To check it properly, get the value from somewhere that does not go through this connection, such as your provider's console, or from the person who runs the server. On the server:

sudo ssh-keygen -lf /etc/ssh/ssh_host_ed25519_key.pub

Compare the values, or paste the correct fingerprint at the prompt instead of yes, and ssh compares for you. In our test the right value was accepted, and a wrong one got Please type 'yes', 'no' or the fingerprint:.

ssh-keyscan and its trust problem

ssh-keyscan -t ed25519 server >> ~/.ssh/known_hosts

This fetches a server's public key and is commonly seen in setup scripts and CI jobs. The problem is that it checks nothing. It records whatever answered, so an attacker on the path gets their key recorded, and the attack is then invisible from that moment on.

It is fine when you verify the result afterward:

ssh-keyscan -t ed25519 server | ssh-keygen -lf -

For CI, it is better to store the expected known_hosts line as a value in your pipeline, and write that to the file.

StrictHostKeyChecking values

ValueNew hostChanged key
ask (default)Asks youRefuses
yesRefusesRefuses
accept-newAdds itRefuses
no or offAdds itConnects, with restrictions

accept-new is the sensible choice for automation: it trusts on first use and catches later changes. yes is the strictest, and it suits fleets where you distribute known_hosts yourself. With it, an unknown host gives:

No ED25519 host key is known for server and you have requested strict checking.
Host key verification failed.

Avoid no. It connects to a host whose key has changed, which is the case this file exists to catch.

UpdateHostKeys

A server can tell a client about all its host keys after login. With UpdateHostKeys, the client adds them to known_hosts, which lets an administrator add a new key, wait for clients to learn it, and then remove the old one with no warnings. We tested UpdateHostKeys=yes: starting with only the ED25519 entry, a login added RSA and ECDSA lines.

The manual says it is on by default if you have not changed UserKnownHostsFile and have not enabled VerifyHostKeyDNS. It only accepts keys from a host already trusted through your own file, not a global file, and it does not apply when the host authenticated with a certificate.

SSHFP: fingerprints in DNS

Host key fingerprints can also be published in DNS as SSHFP records. This prints the records to add for a server, run on that server:

ssh-keygen -r example.com

Clients use them with VerifyHostKeyDNS yes. It is only trusted automatically when the DNS answer is secure, which in practice means signed zones and a resolver that validates them. Otherwise it behaves like ask: it shows you the match, and you still confirm. The default is no.

Questions

Where is the known_hosts file?

In ~/.ssh/known_hosts in your home folder, on any system with OpenSSH. A system-wide file can also exist at /etc/ssh/ssh_known_hosts.

Is it safe to delete known_hosts?

It holds only public keys, so nothing secret is lost. But ssh then asks about every server again, and you lose the check that catches a changed key. Remove one host with ssh-keygen -R instead.

How do I remove one host from known_hosts?

Run ssh-keygen -R server, written as '[server]:2222' if the port is not 22. It works on hashed files too.

Sources

More in Error messages

All guides