Stop your Ansible runners from turning into zombies when SSH hangs
By Saket Jain Published Linux/Unix
Stop your Ansible runners from turning into zombies when SSH hangs
Technical Briefing | 7/24/2026
You probably have an Ansible playbook running on a CI server somewhere that stays green ninety-nine percent of the time. But every once in a while, it just hangs. Not a failure, not an error, just an infinite wait for an SSH connection that never comes. Most people just reach for the cancel button, but the underlying process stays alive, locking up resources and causing a pileup of orphan SSH connections that slowly eat your memory.
Why the default timeout is a lie
Ansible delegates the heavy lifting to OpenSSH. The default settings in your ssh_config are often too optimistic for a CI environment where nodes go offline without warning. If the underlying TCP connection stalls in a half-open state, the client won’t necessarily time out quickly. You need to force the handshake to give up if the server isn’t responding, rather than waiting for the kernel to eventually decide the socket is dead.
ansible-playbook site.yml -e 'ansible_ssh_common_args=-o ConnectTimeout=10 -o ServerAliveInterval=15 -o ServerAliveCountMax=2'
- ConnectTimeout forces the initial socket connection to fail fast if the host is down.
- ServerAliveInterval sends a packet to the server to ensure the session is still active.
- ServerAliveCountMax terminates the connection if those heartbeats fail to receive a response.
Cleaning up the mess when things go sideways
Even with tight timeouts, sometimes you get ghost connections that persist. Don’t rely on the CI job status alone to monitor the health of your runners. If you find your CI nodes have dozens of idle ssh processes, check your connection multiplexing settings in ansible.cfg. Disable ControlPersist if you notice those sockets lingering long after the playbook finishes, because a hung master socket will keep an entire chain of jobs waiting forever.
Next time a pipeline hangs, skip the reboot and check your socket list with ss -tulpn. You might find your answer in the connection state instead of the logs.
