How to Use ssh keyscan and Manage known hosts Step by Step
Manage SSH known_hosts with ssh-keyscan: fetch host keys safely, verify fingerprints, hash entries, remove stale ones and use accept-new in automation.

The first time you connect to a server, SSH asks you to trust its key. In scripts and CI there is nobody to answer, and the lazy fix, disabling the check, removes the protection against impersonation. ssh-keyscan collects keys in advance, so the question is answered once, deliberately. This post covers fetching, verifying and cleaning the file, as a companion to verifying host key fingerprints. The commands assume OpenSSH 10.0.
Fetch a key
ssh-keyscan -t ed25519 web1.example.org
ssh-keyscan -t ed25519 -p 2222 web1.example.org# web1.example.org:22 SSH-2.0-OpenSSH_10.0
web1.example.org ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJq...
The comment line goes to stderr, and the key line is in the known_hosts format: host name, key type, key. Restricting the type with -t avoids collecting several. ed25519 is the type most servers prefer today; if a server offers only RSA, scan rsa.
Verify before trusting
ssh-keyscan -t ed25519 web1.example.org 2>/dev/null | ssh-keygen -lf -256 SHA256:3f2a1c9d8b7e6a5f4c3b2a1908f7e6d5c4b3a291807f6e5d4c3b2a1908f7e6d5 web1.example.org (ED25519)
Compare this fingerprint with one obtained another way: the provider's console output, a record in your inventory, or ssh-keygen -lf /etc/ssh/ssh_host_ed25519_key.pub run on the server through a trusted channel. Scanning over the same untrusted network that an attacker could intercept only repeats the attacker's answer, so a scan without verification gives convenience, not security. Only after the fingerprint matches do you add the entry:
ssh-keyscan -t ed25519 -H web1.example.org >> ~/.ssh/known_hosts-H hashes the host name, so the file no longer lists the servers you visit, which limits what malware gains from reading it. The cost is that you cannot grep it by name; use ssh-keygen -F.
Find and remove entries
ssh-keygen -F web1.example.org
ssh-keygen -R web1.example.org-F finds an entry, hashed or not, and -R removes it and saves the old file as known_hosts.old. Do this after a legitimate rebuild of a server; an unexpected change is a warning to investigate, and the changed host identification error explains how to tell them apart.
Automation
ssh -o StrictHostKeyChecking=accept-new [email protected] uptimeaccept-new (OpenSSH 7.6 and later) writes unknown hosts to the file without asking, but refuses a host whose key has changed, which keeps the important protection. It is much better than StrictHostKeyChecking=no, which accepts changed keys too. In CI, a pre-verified file kept in the repository, pinned to fingerprints you checked once, is stronger still. A certificate authority line, @cert-authority *.example.org ssh-ed25519 AAAA..., removes per-host management; see SSH certificates.
Where this does not apply
Hosts behind load balancers that share a name but not a key produce constant mismatches; give all backends the same host key or connect to each by its own name. Cloud instances that regenerate keys on every rebuild need the fingerprint published at creation. See the SSH config file to set options per host.
What a known hosts entry records
Each line in ~/.ssh/known_hosts ties a host name or address to a public host key and its type. When you connect, the client compares the key the server presents with the recorded one, and refuses to continue silently if they differ, which is the protection against someone impersonating the server. The first connection has no record, so the client asks you to accept a fingerprint, a model called trust on first use. That first decision is the weak point: accepting without checking means a person in the middle at that moment is trusted from then on. The entries may be hashed, with HashKnownHosts on by default in many distributions, so the host names are not readable in the file, and tools like ssh-keygen -F and -R search and remove by name anyway. Port matters too, since a host on a non-standard port is recorded as [host]:port.
A server has several host keys, one per algorithm, and the client records the one it negotiated. A later connection that negotiates a different algorithm after a client upgrade can add a second entry for the same host, which is normal and not a sign of trouble.
Why keyscan alone is not verification
The command ssh-keyscan connects to a host and prints the keys it offers, in the format of a known hosts line. It does not authenticate anything: an attacker who can intercept the connection answers with their own key and keyscan reports it faithfully. So scanning and then adding the result to the file is the same trust-on-first-use decision, made by a script, and no more secure than clicking yes. Verification needs a second channel. Compare the fingerprint it reports, shown with ssh-keygen -lf, with one obtained another way: the provider's console output at the first boot, a record you wrote down when you built the server, an SSHFP DNS record protected by DNSSEC, or a host certificate signed by a CA you trust. For servers you build yourself, print the fingerprint at the end of provisioning and store it with the inventory. The effort pays when a key changes, since you can tell a rebuild from an attack.
Cleaning up and using it in automation
When a server is rebuilt, its key changes and the client refuses to connect, quoting the file and line number. Remove the stale entry with ssh-keygen -R host, which also keeps a backup file, then verify the new fingerprint before accepting it, since the same warning appears during an attack. In automation, such as a CI job that deploys over SSH, avoid disabling verification. Put the expected host keys, taken from a verified source, in a file in the repository or in the CI secrets, copy them to the job's known hosts file, and keep strict checking on. If the key rotates, an update to that file is a reviewed change and a failed job is the alarm you want. Use the -t ed25519 option to scan only the key type you rely on, and the -H option when you want hashed names in the output.
Keeping the file tidy over time
A known hosts file grows for years and fills with entries for servers that no longer exist, with addresses that were reused by other machines, and with duplicate lines from different key types. Reused addresses are the source of many false alarms, as a new server at an old address presents a new key. Remove entries for retired hosts when you retire them, and prefer names to addresses so the record follows the host. Hashing hides names from someone who steals the file, though it makes manual cleanup harder, so list entries with ssh-keygen -F for a name you know. Keep the file for shared automation separate from personal files, set with UserKnownHostsFile, so rotating a key in one place does not break the other. A short yearly review of the file takes minutes, and avoids the confusion of an alarm that is only a stale line.


