You've started a playbook run, and now you're watching the cursor blink. And blink. And blink some more. Finally, after what feels like forever: FAILED! => {"msg": "timed out"}. Connection timeouts are among the most frustrating Ansible issues because they can stem from so many different causes.
Let's systematically diagnose and fix these timeout problems.
Understanding the Error
Connection timeout errors manifest in different ways:
TASK [Gather Facts] ***********************************************************
fatal: [webserver01]: UNREACHABLE! => {"changed": false, "msg": "Failed to connect to the host via ssh: ssh: connect to host 192.168.1.100 port 22: Connection timed out", "unreachable": true}Or during command execution:
fatal: [webserver01]: FAILED! => {"msg": "Timeout (12s) waiting for privilege escalation prompt: "}The first indicates network connectivity issues. The second suggests problems with command execution or privilege escalation.
Step 1: Identify the Timeout Type
First, determine where the timeout occurs:
# Test basic SSH connectivity
time ssh -o ConnectTimeout=10 ansible_user@192.168.1.100 'echo connected'If this times out, you have a network issue. If it succeeds quickly, the problem is with Ansible's SSH configuration or command execution.
Step 2: Check Network Connectivity
Run basic network diagnostics:
```bash # Test reachability ping -c 5 192.168.1.100
# Check if port is open nc -zv 192.168.1.100 22 # Or with timeout timeout 5 bash -c 'cat < /dev/null > /dev/tcp/192.168.1.100/22 && echo "Port open" || echo "Port closed/filtered"' ```
For cloud instances, verify security groups and network ACLs allow your IP:
```bash # For AWS, check security group rules aws ec2 describe-security-groups --group-ids sg-xxxxx --query 'SecurityGroups[0].IpPermissions'
# The port should show your IP or 0.0.0.0/0 ```
Step 3: Adjust Ansible Timeout Settings
Ansible's default timeout is 10 seconds, which might be too short for slow networks. Increase it in your ansible.cfg:
```ini [defaults] timeout = 60
[ssh_connection] ssh_args = -o ConnectTimeout=60 -o ControlMaster=auto -o ControlPersist=60s ```
Or at runtime:
ansible-playbook -i inventory deploy.yml --timeout 60For specific tasks, use async for long-running operations:
- name: Long running operation
command: /opt/app/slow-install.sh
async: 3600
poll: 30Step 4: Optimize SSH Control Path
SSH Control Master creates persistent connections but can cause timeout issues. Check for stale connections:
```bash # List existing control sockets ls -la ~/.ansible/cp/
# Remove stale sockets rm -rf ~/.ansible/cp/* ```
Adjust your SSH connection settings:
[ssh_connection]
ssh_args = -o ControlMaster=auto -o ControlPersist=300s -o ControlPath=/tmp/ansible-ssh-%h-%p-%r
pipelining = TrueThe ControlPersist value (300s) determines how long the connection stays open after the last task. Increase for multiple playbooks, decrease if connections go stale.
Step 5: Debug with Verbose SSH Output
See exactly what SSH is doing:
ansible webserver01 -i inventory -m ping -vvv 2>&1 | grep -A 5 "timeout"For even more detail, test SSH directly with maximum verbosity:
ssh -vvv -o ConnectTimeout=30 ansible_user@192.168.1.100Look for clues in the output:
- debug1: connect to address ... port 22: Connection timed out - Network issue
- debug1: Authentications that can continue: publickey - Key not accepted yet
- debug1: Waiting for server authentication - Server slow to respond
Step 6: Handle Slow DNS Resolution
If DNS resolution is slow, SSH waits during connection. Bypass DNS for SSH:
# Test if DNS is the culprit
time nslookup webserver01If slow, add to ansible.cfg:
[ssh_connection]
ssh_args = -o ConnectTimeout=60And use IP addresses in inventory, or add to /etc/hosts:
echo "192.168.1.100 webserver01" | sudo tee -a /etc/hostsStep 7: Fix Privilege Escalation Timeouts
Timeouts during become operations need different handling:
- name: Task requiring sudo
become: yes
apt:
name: nginx
state: presentIf this times out waiting for sudo password, either:
Option A: Configure passwordless sudo:
# On target host
echo "ansible_user ALL=(ALL) NOPASSWD: ALL" | sudo tee /etc/sudoers.d/ansible_userOption B: Provide password in playbook:
ansible-playbook -i inventory deploy.yml --ask-become-passOption C: Store in vault:
ansible_become_password: "{{ vault_become_password }}"Increase become timeout:
[privilege_escalation]
become_timeout = 60Step 8: Handle Network Latency
For high-latency networks (cross-region, satellite), adjust multiple timeouts:
```ini [defaults] timeout = 120 gather_timeout = 60
[ssh_connection] ssh_args = -o ConnectTimeout=120 -o ServerAliveInterval=30 -o ServerAliveCountMax=5 pipelining = True retries = 3 ```
The ServerAliveInterval keeps connections alive during idle periods.
Step 9: Optimize Fact Gathering
Fact gathering can timeout on systems with many network interfaces or slow disks:
[defaults]
gather_timeout = 60
gathering = smart
fact_caching = jsonfile
fact_caching_timeout = 86400
fact_caching_connection = /tmp/ansible_factsOr skip fact gathering entirely when not needed:
- name: Quick task
hosts: all
gather_facts: no
tasks:
- name: Simple command
command: echo "done"Step 10: Handle Proxy and Bastion Hosts
If connecting through a bastion host, timeouts compound. Configure SSH proxy:
[ssh_connection]
ssh_args = -o ProxyCommand="ssh -W %h:%p -q bastion.example.com"Or in inventory:
all:
hosts:
webserver01:
ansible_host: 192.168.1.100
ansible_ssh_common_args: '-o ProxyCommand="ssh -W %h:%p -q bastion.example.com"'Increase timeouts for proxied connections:
```ini [defaults] timeout = 120
[ssh_connection] ssh_args = -o ConnectTimeout=120 -o ServerAliveInterval=60 ```
Step 11: Monitor Connection Performance
Use timing callbacks to identify slow tasks:
export ANSIBLE_CALLBACK_WHITELIST=profile_tasks
ansible-playbook -i inventory deploy.ymlOutput shows which tasks take longest:
Friday 04 April 2026 10:00:00 +0000 (0:00:15.234) 0:00:15.234 ****
TASK [Gather Facts] ***********************************************************Quick Verification
Test your fixes:
```bash # Basic connectivity ansible all -i inventory -m ping -T 60
# With timing time ansible all -i inventory -m ping ```
Successful output:
webserver01 | SUCCESS => {
"changed": false,
"ping": "pong"
}Prevention Checklist
Add to your ansible.cfg:
```ini [defaults] timeout = 60 gather_timeout = 60 gathering = smart fact_caching = jsonfile fact_caching_timeout = 3600
[ssh_connection] pipelining = True ssh_args = -o ControlMaster=auto -o ControlPersist=300s -o ControlPath=/tmp/ansible-ssh-%h-%p-%r retries = 3
[privilege_escalation] become_timeout = 60 ```
Connection timeouts require patience and systematic debugging. Start with basic network tests, adjust timeouts, optimize SSH settings, and configure appropriate caching for your environment.