SSH StrictHostKeyChecking yes, accept-new, ask and no: how known_hosts handles new and changed host keys

How the OpenSSH client treats an unknown or changed host key under each StrictHostKeyChecking value, the known_hosts line format, and ssh-keygen -F, -R and -H, per OpenBSD manuals and RFC 4251.

sshopensshknown_hostssecurity

The first time you connect to a server over SSH, the client doesn’t know that server’s host key yet. A server you have used before can also turn up with a key that differs from the one you saw last time. The OpenSSH client decides what to do in each case from the StrictHostKeyChecking option, and the keys it compares against live in known_hosts files. Before putting StrictHostKeyChecking=no into an automation script, it’s worth knowing exactly what each value lets through.

This post is based on the OpenBSD-current manual pages on the OpenBSD manual server, ssh_config(5) (page dated October 9, 2026), sshd(8) (September 2, 2026) and ssh-keygen(1) (October 1, 2026), plus RFC 4251, which defines the SSH protocol architecture. All were checked on 2026-10-19. The OpenSSH shipped with a Linux distribution or macOS may be a different version with different defaults or options, so check man ssh_config on your own system. SSH implementations other than OpenSSH are out of scope. The ssh(1) manual, which describes the exact warning text and the host key verification process in detail, was not used as a source here, so this post doesn’t quote it.

What host key checking protects against

RFC 4251 §4.1 says the server host key is used during key exchange to verify that the client is really talking to the correct server. For that to work, the client must know the server’s public host key in advance. The RFC describes two trust models:

  • The client keeps a local database that maps each host name (as typed by the user) to its public host key. No central infrastructure is needed, but the database can become a burden to maintain.
  • A trusted certification authority (CA) certifies the name-to-key association. The client only needs to know the CA root key.

OpenSSH’s known_hosts is the database of the first model. The @cert-authority marker covered below is how the second model is used inside the same file.

The same section notes that the protocol allows the name-to-key association to go unchecked on the first connection. That connection still protects against passive eavesdropping but is open to active man-in-the-middle (MITM) attacks, so implementations SHOULD NOT normally allow it by default. As an example strategy, the RFC suggests accepting a host key without checking only the first time, saving it in a local database and comparing against it on every later connection. It also says all implementations SHOULD provide an option not to accept host keys that cannot be verified.

§9.3.4 explains that if the server’s key was distributed securely beforehand, a key offered by a man in the middle won’t match the stored one, and the user SHOULD be warned. Its conclusion is that using the protocol without a reliable binding between a host and its host keys is inherently insecure and NOT RECOMMENDED.

Where the client looks for keys

According to ssh_config(5), the client reads two kinds of files:

Option Default Meaning
UserKnownHostsFile ~/.ssh/known_hosts, ~/.ssh/known_hosts2 Per-user host key database. none makes the client ignore per-user files.
GlobalKnownHostsFile /etc/ssh/ssh_known_hosts, /etc/ssh/ssh_known_hosts2 System-wide host key database

The SSH_KNOWN_HOSTS FILE FORMAT section of sshd(8) says the global file is prepared by the administrator (and is optional), and describes the per-user file as maintained automatically, with an unknown host’s key added whenever the user connects to it. Whether the client actually adds a key on its own depends on client policy and configuration: as the StrictHostKeyChecking table below shows, yes never adds one automatically and ask adds one only after the user confirms. The two files can contain conflicting information; authentication is accepted if valid information can be found in either. If KnownHostsCommand is set, the client runs that command after reading the files to get more host key lines in the same format. If the command exits abnormally or returns a non-zero status, the connection is terminated.

What each StrictHostKeyChecking value does

Splitting the ssh_config(5) description into a new host (no key stored yet) and a changed key (stored key differs) gives this:

Value New host key Changed host key
yes Never added automatically. The user must add every new host by hand. Refuses to connect.
accept-new Added automatically to the user’s known_hosts file. Connection not permitted.
ask (default) Added only after the user confirms. Refuses to connect.
no or off Added automatically to the user known hosts files. Connection allowed to proceed, “subject to some restrictions”.

The manual adds that the host keys of known hosts are verified automatically in all cases. In other words, this option changes what happens when a key is missing or different. It never switches off the comparison against a stored key.

In the manual’s words, yes provides maximum protection against MITM attacks, though it can be annoying when /etc/ssh/ssh_known_hosts is poorly maintained or when you connect to new hosts often.

ssh_config(5) doesn’t spell out what the “restrictions” for no are. They are covered in ssh(1), which this post doesn’t use as a source, so they aren’t described here. What the table does show is that no (off) is the only one of the four values that doesn’t refuse the connection when the key has changed.

Which value to pick

This section is a judgement drawn from the manual and the RFC.

  • accept-new has the same shape as the “accept the first time, save it, compare from then on” strategy that RFC 4251 §4.1 gives as an example. For automated jobs where you can accept the premise that the first connection goes over a safe path, it runs without an interactive prompt and still blocks changed keys. It does nothing to confirm that the key received on that first connection is genuine.
  • yes fits when you can distribute keys in advance. sshd(8) recommends not typing known_hosts lines by hand, but generating them with a script or ssh-keyscan(1), or by taking a server’s /etc/ssh/ssh_host_*_key.pub and adding host names at the front. Fetching keys over the network has the same problem as a first connection unless you check the fetched key some other way. RFC 4251 §9.3.4 encourages server administrators to make fingerprints available through a means that doesn’t rely on the integrity of the host keys themselves (secured web pages, paper and so on).
  • no is the only value that does not categorically refuse a connection when the host key has changed. The connection proceeds only “subject to some restrictions”, and ssh_config(5) doesn’t say the changed key is accepted or stored. Even so, it comes close to exactly the usage RFC 4251 §9.3.4 marks as NOT RECOMMENDED.

The format of a known_hosts line

According to the SSH_KNOWN_HOSTS FILE FORMAT section of sshd(8), each line may contain the following space-separated fields: marker (optional), hostnames, key type, base64-encoded key and comment (optional). Because the marker and comment are optional, the example below includes lines with only three or four fields. The comment runs to the end of the line and is not used. Lines starting with # and empty lines are ignored.

Here is the example file from sshd(8), split into its lines (the key values are abbreviated in the original as well):

# Comments allowed at start of line
cvs.example.net,192.0.2.10 ssh-rsa AAAA1234.....=
# A hashed hostname
|1|JfKTdBh7rNbXkVAQCRp4OQoPfmI=|USECr3SWf1JUPsms5AqfD5QfxkM= ssh-rsa AAAA1234.....=
# A revoked key
@revoked * ssh-rsa AAAAB5W...
# A CA key, accepted for any host in *.mydomain.com or *.mydomain.org
@cert-authority *.mydomain.org,*.mydomain.com ssh-rsa AAAAB5W...

The rules for the hostnames field:

  • It is a comma-separated list of patterns, with * and ? as wildcards. A pattern preceded by ! is negated: if the name matches a negated pattern, that line doesn’t accept it even if another pattern on the line matched.
  • For a non-standard port, put the name or address in square brackets followed by a colon and the port: [host]:port.
  • Hashed names start with |. Only one hashed name may appear on a line, and negation and wildcards can’t be used with it.

When the client is authenticating a server, the name matched against these patterns is the host name the user gave. If HostKeyAlias is set, its value is used instead, and if the CanonicalizeHostname option was used, the canonical server name is. ssh_config(5) describes HostKeyAlias as useful for tunnelling SSH connections or for several servers running on one host.

There are two markers. @cert-authority means the key on that line is a CA key. When a server presents a certificate, authentication is accepted if the key of the CA that signed it is on a line with this marker. @revoked marks a revoked key: it is never accepted for authentication or as a CA, and ssh(1) prints a warning when it encounters one. Several lines or different keys for the same name are permitted, but not recommended.

With CheckHostIP set to yes, the client also checks the host’s IP address in known_hosts. The manual says this detects a host key that changed because of DNS spoofing, and that in the process it adds destination addresses to ~/.ssh/known_hosts regardless of the StrictHostKeyChecking setting. The current default is no.

Editing known_hosts with ssh-keygen

ssh-keygen(1) has three options for editing known_hosts. The commands below illustrate usage; they were not run while writing this post. server.example.net is an example name.

# Find and print the lines for a host (hashed names are found too)
ssh-keygen -F server.example.net -f ~/.ssh/known_hosts

# Remove every key for a host; for a non-standard port use [name]:port
ssh-keygen -R '[server.example.net]:2222' -f ~/.ssh/known_hosts

# Replace every host name and address in the file with its hash
ssh-keygen -H -f ~/.ssh/known_hosts
  • -F searches a known_hosts file for the given host name (optionally with a port) and lists any occurrences. It’s useful for finding hashed names.
  • -R removes all keys belonging to the given host name (optionally with a port). It’s useful for deleting hashed hosts.
  • -H replaces all host names and addresses with hashed forms and moves the original content to a file with a .old suffix. It leaves already-hashed names alone, so it is safe on files that mix hashed and plain names.

The examples pass -f explicitly because the manual text checked here doesn’t say which file is used when -f is left out. Note too that the .old file left behind by -H still holds the names in plain form. If you hashed the file to hide names, that file needs dealing with as well; this is a conclusion drawn from the description above.

To hash new lines as they are added, turn on HashKnownHosts in ssh_config(5). The default is no, and enabling it does not convert names already in the file, so you still need ssh-keygen -H for those.

When you hit a changed key

Even with a solid reason, such as a reinstalled server or a rotated key, deleting the line with -R and reconnecting turns the new key back into a “never seen before” key. Following RFC 4251 §9.3.4, the order is to check the new fingerprint through a path unrelated to the host key itself, and only then accept it. This order applies the RFC’s recommendation to a practical procedure; it isn’t a procedure the manual prescribes.

UpdateHostKeys for key rotation

If you plan to rotate keys on the server side, UpdateHostKeys in ssh_config(5) is relevant. With it on, the client accepts notifications of additional host keys that the server sends after authentication and adds them to UserKnownHostsFile. The server can send replacement public keys before the old ones are removed, which allows graceful rotation.

Additional keys are accepted only if all of the following hold:

  • The key used to authenticate the host was already trusted or explicitly accepted by the user.
  • The host was authenticated via UserKnownHostsFile, not GlobalKnownHostsFile.
  • The host was authenticated with a plain key, not a certificate.

UpdateHostKeys is on by default if the user hasn’t overridden the default UserKnownHostsFile and hasn’t enabled VerifyHostKeyDNS; otherwise it is set to no. With ask, the user is asked to confirm changes to known_hosts, but that confirmation is currently incompatible with ControlPersist and is disabled when it is enabled. The manual says that at present only sshd(8) from OpenSSH 6.8 and later supports the “hostkeys@openssh.com” extension this feature uses.

Things to check

  • Search config files and scripts for StrictHostKeyChecking no (or off). If the goal is automation, see whether accept-new is enough.
  • Decide how the key from the first connection gets confirmed. If you can distribute keys in advance, use yes together with a global or per-user known_hosts.
  • Servers on non-standard ports are stored and removed as [name]:port; account for that when using -F and -R.
  • If you ran ssh-keygen -H, decide what to do with the .old file.
  • Check that the defaults in this post (ask, HashKnownHosts no, CheckHostIP no, the UpdateHostKeys conditions) match the manual for the OpenSSH you actually run.

References

All checked on 2026-10-19. The manual pages are the OpenBSD-current versions.

Back to the blog