Introduction
Mitogen is a Python library that replaces Ansible's default SSH + SFTP module execution with a single persistent Python-to-Python channel. Instead of opening multiple SSH connections per task (upload module, execute, download result), Mitogen sends pure Python bytecode over one connection. The result: 2x to 10x faster playbook execution with zero changes to your playbooks. The trade-off: compatibility limitations with some Ansible features.
How Default Ansible Works
For each task on each host, Ansible's default strategy:
1. Open SSH connection
2. Create temp directory on remote
3. SFTP upload module + arguments
4. SSH execute module
5. SSH read stdout/stderr
6. SSH delete temp files
7. Close connection
That's 5-7 SSH round trips per task per host. With 50 tasks on 100 hosts, that's up to 35,000 SSH operations.
How Mitogen Works
1. Open one persistent SSH connection
2. Bootstrap a Python interpreter on the remote
3. Send module bytecode over the existing connection
4. Execute in-process, return results over the same channel
One connection per host for the entire playbook run. Modules execute as pure Python functions — no temp files, no SFTP, no repeated SSH handshakes.
┌─────────────┐ ┌─────────────┐
│ Controller │───── 1 SSH ─────│ Target │
│ (Ansible) │ channel │ (Python) │
│ │◄────────────────│ │
│ Send module │ bytecode + │ Execute │
│ bytecode │ results flow │ in-process │
│ │ over same │ │
│ │ connection │ │
└─────────────┘ └─────────────┘
Install
# Install Mitogen
pip install mitogen
# Find the path
python3 -c "import mitogen; print(mitogen.__path__[0])"
# /home/user/.local/lib/python3.12/site-packages/mitogen
Configure
ansible.cfg
[defaults]
strategy_plugins = /path/to/mitogen/ansible_mitogen/plugins/strategy
strategy = mitogen_linear
Or with environment variable:
export ANSIBLE_STRATEGY_PLUGINS=/path/to/mitogen/ansible_mitogen/plugins/strategy
export ANSIBLE_STRATEGY=mitogen_linear
Dynamic Configuration
# In playbook — use Mitogen for specific plays
- name: Fast configuration tasks
hosts: webservers
strategy: mitogen_linear
tasks:
- name: Install packages
ansible.builtin.apt:
name: nginx
state: present
Per-Environment Configuration
# ansible.cfg for production (use Mitogen)
[defaults]
strategy = mitogen_linear
strategy_plugins = /opt/venv/lib/python3.12/site-packages/mitogen/ansible_mitogen/plugins/strategy
# Mitogen-specific tuning
[mitogen]
# Maximum concurrent interpreters per host
# (default: number of CPUs on controller)
Benchmarks
Typical results on a 50-host fleet running a 30-task playbook:
| Metric | Default SSH | Mitogen | Improvement |
|---|---|---|---|
| Wall time | 12 min | 2 min | 6x faster |
| SSH connections | ~1,500 | 50 | 97% fewer |
| Network bytes | ~200 MB | ~15 MB | 93% less |
| CPU (controller) | Low | Moderate | Expected |
| Temp files created | ~1,500 | 0 | Zero disk I/O |
Quick Benchmark
# Without Mitogen
time ansible-playbook -i inventory site.yml
# real 12m34s
# With Mitogen
ANSIBLE_STRATEGY=mitogen_linear \
ANSIBLE_STRATEGY_PLUGINS=/path/to/mitogen/ansible_mitogen/plugins/strategy \
time ansible-playbook -i inventory site.yml
# real 1m58s
What Works Well
- All standard modules —
apt,yum,copy,template,file,service,user, etc. - Roles and includes — no changes needed
- Handlers — work normally
- Variables and facts — fully supported
- Vault-encrypted variables — works
- become/sudo — supported (Mitogen handles privilege escalation internally)
- Multi-platform — Linux, macOS targets
- Large inventories — scales well with 100+ hosts
Known Limitations
Not Compatible With
| Feature | Status | Workaround |
|---|---|---|
raw module | ❌ Not supported | Use command or shell |
script module | ❌ Not supported | Copy script + execute |
synchronize (rsync) | ⚠️ Partial | Use copy for small files |
| Custom connection plugins | ❌ Replaced by Mitogen | Can't stack |
ansible_ssh_common_args | ⚠️ Partial | Some SSH options ignored |
| Windows (WinRM) | ❌ Not supported | SSH targets only |
| Network devices (CLI) | ❌ Not supported | SSH + Python targets only |
async tasks | ⚠️ Partial | May not work with all modules |
Version Compatibility
Mitogen 0.3.x → ansible-core 2.15, 2.16, 2.17
Mitogen 0.2.x → ansible-core 2.10-2.14 (legacy)
Check the Mitogen changelog for latest compatibility.
Strategies
Mitogen provides drop-in replacements for Ansible's built-in strategies:
| Ansible Strategy | Mitogen Equivalent |
|---|---|
linear | mitogen_linear |
free | mitogen_free |
host_pinned | mitogen_host_pinned |
# ansible.cfg
[defaults]
strategy = mitogen_free # Maximum parallelism
Combining with Other Optimizations
# ansible.cfg — maximum performance
[defaults]
strategy = mitogen_linear
strategy_plugins = /path/to/mitogen/ansible_mitogen/plugins/strategy
forks = 50
gathering = smart
fact_caching = jsonfile
fact_caching_connection = /tmp/ansible-facts
fact_caching_timeout = 86400
[connection]
pipelining = true # Still helps for non-Mitogen fallback
[ssh_connection]
ssh_args = -o ControlMaster=auto -o ControlPersist=60s
Troubleshooting
"No module named 'mitogen'"
# Verify installation
pip show mitogen
python3 -c "import mitogen; print(mitogen.__path__[0])"
# Use absolute path in ansible.cfg
strategy_plugins = /home/user/.local/lib/python3.12/site-packages/mitogen/ansible_mitogen/plugins/strategy
"Target has no Python interpreter"
Mitogen needs Python on the target:
# Bootstrap Python first (without Mitogen)
ansible -i inventory all -m raw -a "apt install -y python3" \
-e ansible_strategy=linear
Task Fails Under Mitogen but Works Without
# Fall back to default strategy for problematic plays
- name: Tasks needing raw/script modules
hosts: targets
strategy: linear # Use default SSH strategy
tasks:
- name: Run raw command
ansible.builtin.raw: echo hello
Debug Mitogen Issues
# Enable Mitogen debug logging
MITOGEN_LOG_LEVEL=debug ansible-playbook site.yml 2>mitogen-debug.log
When to Use Mitogen
Use Mitogen when:
- Managing 10+ Linux/macOS hosts
- Playbooks take >5 minutes
- Running many small tasks (package installs, file operations, service management)
- Network bandwidth to targets is limited
- You want faster CI/CD feedback
Don't use Mitogen when:
- Managing Windows hosts (WinRM)
- Managing network devices (Cisco IOS, Arista EOS, etc.)
- Using
raw,script, orsynchronizemodules heavily - You need bleeding-edge ansible-core features (wait for Mitogen support)
Alternative: Pipelining
If Mitogen doesn't fit, enable SSH pipelining for a smaller speedup:
# ansible.cfg
[connection]
pipelining = true
[ssh_connection]
ssh_args = -o ControlMaster=auto -o ControlPersist=600s
This reduces SSH operations per task from ~7 to ~3 (no SFTP, executes via stdin).
Related Articles
Conclusion
Mitogen replaces Ansible's SSH + SFTP module execution with a single persistent Python channel per host — reducing SSH connections by 97%, network traffic by 93%, and wall time by 2-10x. Install it with pip install mitogen, add two lines to ansible.cfg, and your existing playbooks run faster with zero modifications. The main trade-off is compatibility: raw, script, Windows, and network device modules don't work under Mitogen, so use strategy: linear for those specific plays.