You rebuild a VPS, restore a snapshot, or point an old hostname at a new IP, then run the same ssh command you've run a hundred times before — and instead of a login prompt, your terminal fills up with a red warning about a "man-in-the-middle attack" and refuses to connect. Nothing was actually attacked. Your SSH client is just doing exactly what it's supposed to do.
Symptom: SSH Refuses to Connect After a Rebuild or IP Change
The full warning usually looks something like this:
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!
Someone could be eavesdropping on you right now (man-in-the-middle attack)!
It is also possible that a host key has just been changed.
The fingerprint for the ECDSA key sent by the remote host is
SHA256:AbCdEfGhIjKlMnOpQrStUvWxYz1234567890ABCDEF
Host key verification failed.
It typically shows up right after one of these:
- You reinstalled the OS on your VPS, or restored it from a snapshot/backup.
- Your hosting provider migrated your VPS to new hardware and it came back with a new IP.
- You reused an IP address that used to belong to a different server (common with cheap VPS plans where IPs get recycled).
- You're SSHing into a load balancer or reverse proxy that now routes to a different backend box.
SCP, SFTP clients, rsync, Ansible, and CI/CD deploy scripts hit the exact same wall — they all rely on the same SSH host key check under the hood.
Cause: Your Client Remembers the Old Server's Fingerprint
Every SSH server generates a host key pair the first time it boots. When you connect to a server for the first time, your SSH client saves that server's public key fingerprint in ~/.ssh/known_hosts, keyed to the IP or hostname. Every connection after that, it compares the fingerprint the server presents against the one it saved.
That comparison is the entire point of host key checking — it's what stops someone from silently swapping in a rogue server at the same IP and stealing your credentials. The problem is that a legitimate server rebuild generates a new host key too, so your client sees a mismatch and can't tell the difference between "my provider rebuilt this box" and "someone hijacked this IP." It fails safe, on purpose.
This is different from Permission denied (publickey), which is an authentication problem after the connection is already trusted. Here, the connection gets rejected before authentication is even attempted.
Fix: Remove the Stale Key and Reconnect
The short version: delete the old, now-wrong entry for that host from known_hosts, then let SSH save the new one. Don't just disable the check globally — that throws away the protection for every server you connect to, not just this one.
Step 1 — Remove Just That One Entry
OpenSSH ships a built-in flag for exactly this. Run it from your local machine (not the server):
ssh-keygen -R your-server-ip
If you connect by hostname instead of a raw IP, remove that entry too — both can exist side by side in known_hosts:
ssh-keygen -R your-server.example.com
This edits ~/.ssh/known_hosts in place and leaves every other saved host untouched. You'll see confirmation like /home/you/.ssh/known_hosts updated along with a backup file it created automatically.
Step 2 — Reconnect and Verify the New Fingerprint
ssh user@your-server-ip
You'll get the normal "authenticity of host can't be established" prompt, since this is now treated as a first-time connection. Before typing yes, it's worth actually checking the fingerprint matches your server, especially right after a provider-side migration where you didn't personally trigger the rebuild.
You can pull the current fingerprint straight from most VPS control panels (including SkyServer's), or from the server itself if you still have console/VNC access:
ssh-keygen -lf /etc/ssh/ssh_host_ecdsa_key.pub
Compare that against the SHA256:... line in the warning. If they match, type yes and you're back in.
Step 3 — If You Can't Confirm It, Don't Just Force It
It's tempting to reach for StrictHostKeyChecking=no to make the warning go away. Resist that on a one-off basis — it disables the exact protection that's supposed to catch a real hijack. If you genuinely can't verify the fingerprint (no console access, provider support is slow to respond), open a support ticket and confirm the rebuild before connecting, rather than blindly accepting.
Step 4 — Fix Automation That Broke Too
If a deploy pipeline or cron job also hit this error, it's failing for the same reason your terminal did. For CI/CD specifically, don't bake StrictHostKeyChecking=no into the pipeline permanently. Instead, pin the expected fingerprint once, right after the rebuild:
ssh-keyscan -H your-server-ip >> ~/.ssh/known_hosts
Run that from the CI runner (or commit the refreshed known_hosts entry to your deploy secrets) immediately after you've manually verified the new key is legitimate, not before.
Prevention: Fewer Surprises Next Time
- Ask your provider whether a migration reuses the old host key. Some hosting migrations restore the exact same
/etc/ssh/ssh_host_*files onto the new hardware specifically to avoid this warning; others don't. Knowing which applies to you saves a scare later. - Back up your host keys before a planned rebuild. If you're reinstalling the OS yourself and want to keep the same identity, copy
/etc/ssh/ssh_host_*off the server first and restore them after the reinstall, before startingsshd. - Document fingerprints for production servers. Keep a small internal note (password manager, internal wiki, whatever your team already uses) with the current SHA256 fingerprint for each critical server, so you have something to check against without needing console access under time pressure.
- Avoid IP reuse assumptions. If you're handed a "new" VPS and connect using an IP or hostname you've used before for a different server, expect this warning by default — it's not a bug.
If you're moving to a new SkyServer VPS or restoring from a snapshot and want a hand confirming the host key changed for a legitimate reason, our support team can pull the current fingerprint from the panel side so you're not verifying blind.
Frequently Asked Questions
Is it ever safe to just delete the entire known_hosts file instead of one line?
It's safe in the sense that it won't break anything — SSH will just re-prompt you to trust every server the next time you connect to each one. But it throws away your ability to spot a real hijack on any of those other servers too, so it's better to use ssh-keygen -R and only remove the specific host that changed.
Why does the warning mention an ECDSA key specifically? My server uses Ed25519.
SSH clients check whichever key type they have cached for that host, and the algorithm name shown will match whatever type your client saved on the very first connection. Modern OpenSSH defaults to Ed25519, but older saved entries or servers configured differently can show ECDSA or RSA instead. The fix is the same regardless of key type.
Can I avoid this warning entirely by using a hostname that never changes IP?
Using a stable hostname avoids IP-reuse-triggered warnings, but not rebuild-triggered ones — if the server behind that hostname gets rebuilt and regenerates its host key, you'll still see the mismatch, because the check is against the key, not the address.
My deploy script now fails with "Host key verification failed" in CI. What's the quickest safe fix?
Run ssh-keyscan -H your-server-ip once after confirming the rebuild is legitimate, and store that output as the CI runner's known_hosts entry (as a secret or a committed file, depending on your setup). Avoid StrictHostKeyChecking=no as a permanent pipeline setting — it silently accepts any future key change too, including a malicious one.
I verified the fingerprint and it does NOT match what my provider gave me. What now?
Stop and don't connect. Contact your hosting provider's support directly (through their panel or a known support channel, not a link from the warning) before doing anything else — a genuine mismatch after ruling out a rebuild or IP reuse is exactly the scenario this check exists to catch.
