Introduction
The error "This command has to be run under the root user" is one of the most common Ansible errors for beginners. It occurs when a task requires root (superuser) privileges but the playbook is not configured to escalate privileges. This typically happens with package management, service control, user management, and system configuration tasks.
This article explains why this error occurs, all the ways to fix it, how Ansible privilege escalation works, and best practices for managing sudo access across your infrastructure.
Understanding the Error
When Ansible connects to a remote host, it runs tasks as the SSH user (often a regular non-root user). Many system operations require root privileges:
$ apt install nginx
E: Could not open lock file /var/lib/dpkg/lock-frontend - open (13: Permission denied)
E: Unable to acquire the dpkg frontend lock
The same thing happens in Ansible — the remote module runs as a non-root user and the underlying command fails:
TASK [rsync installed] **********************
fatal: [demo.example.com]: FAILED! => {
"changed": false,
"msg": "This command has to be run under the root user.",
"results": []
}
Error Playbook
This playbook triggers the error because become: false prevents privilege escalation:
---
- name: Troubleshooting under the root user
hosts: all
become: false
tasks:
- name: rsync installed
ansible.builtin.package:
name: rsync
state: present
Error Output
$ ansible-playbook -i inventory playbook.yml
PLAY [Troubleshooting under the root user] ********
TASK [Gathering Facts] *****************************
ok: [demo.example.com]
TASK [rsync installed] *****************************
fatal: [demo.example.com]: FAILED! => {
"changed": false,
"msg": "This command has to be run under the root user.",
"results": []
}
PLAY RECAP *****************************************
demo.example.com : ok=1 changed=0 unreachable=0 failed=1
Solution 1: Enable become at Play Level
The most common fix — add become: true to the play:
---
- name: Install packages
hosts: all
become: true
tasks:
- name: rsync installed
ansible.builtin.package:
name: rsync
state: present
Fixed Output
$ ansible-playbook -i inventory playbook.yml
PLAY [Install packages] ****************************
TASK [Gathering Facts] *****************************
ok: [demo.example.com]
TASK [rsync installed] *****************************
ok: [demo.example.com]
PLAY RECAP *****************************************
demo.example.com : ok=2 changed=0 unreachable=0 failed=0
Solution 2: Enable become at Task Level
If only specific tasks need root, apply become per task:
---
- name: Mixed privilege tasks
hosts: all
become: false
tasks:
- name: Check uptime (no root needed)
ansible.builtin.command: uptime
changed_when: false
- name: Install rsync (root needed)
ansible.builtin.package:
name: rsync
state: present
become: true
- name: Check disk usage (no root needed)
ansible.builtin.command: df -h
changed_when: false
Solution 3: Enable become at Role Level
---
- name: Deploy application
hosts: webservers
roles:
- role: install_packages
become: true
- role: configure_app
become: false
Solution 4: Set become in ansible.cfg
For environments where you always need privilege escalation:
# ansible.cfg
[privilege_escalation]
become = true
become_method = sudo
become_user = root
become_ask_pass = false
Solution 5: Command Line Flag
Override the playbook setting from the command line:
# Enable become
ansible-playbook -i inventory playbook.yml --become
# Specify become method
ansible-playbook -i inventory playbook.yml --become --become-method=sudo
# Specify become user
ansible-playbook -i inventory playbook.yml --become --become-user=root
# Prompt for sudo password
ansible-playbook -i inventory playbook.yml --become --ask-become-pass
How Ansible Privilege Escalation Works
When become: true is set, Ansible:
- Connects to the remote host as the SSH user
- Uploads the module to a temporary directory
- Executes the module via the become method (default:
sudo) - The module runs as the become user (default:
root) - Returns the result and cleans up
Become Directives
| Directive | Default | Description |
|---|---|---|
become | false | Enable privilege escalation |
become_user | root | User to escalate to |
become_method | sudo | Method: sudo, su, pbrun, pfexec, doas, dzdo, ksu, runas |
become_flags | (none) | Additional flags for the become method |
Precedence (highest to lowest)
- Task-level
become - Block-level
become - Role-level
become - Play-level
become - Command line
--become ansible.cfgbecome
Tasks That Require Root
These operations almost always need become: true:
| Task Type | Module Examples |
|---|---|
| Package management | apt, yum, dnf, package, pip (system) |
| Service management | service, systemd |
| User/group management | user, group |
| File ownership changes | file with owner/group |
| System configuration | sysctl, hostname, timezone |
| Firewall rules | firewalld, ufw, iptables |
| Mount operations | mount |
| Cron (for other users) | cron with user |
| SELinux | selinux, seboolean |
Tasks That Do NOT Require Root
| Task Type | Module Examples |
|---|---|
| Reading files | stat, slurp, find (user-accessible paths) |
| Running commands as current user | command, shell |
| Working with user's home | copy, template (to user's home) |
| Debugging | debug, assert, fail |
| Setting facts | set_fact, add_host |
| API calls | uri, get_url (to user-writable paths) |
Sudo Configuration on Target Hosts
For passwordless sudo (most common in automation):
# /etc/sudoers.d/ansible
ansible_user ALL=(ALL) NOPASSWD: ALL
For limited sudo (more secure):
# /etc/sudoers.d/ansible
ansible_user ALL=(ALL) NOPASSWD: /usr/bin/apt, /usr/bin/apt-get, /bin/systemctl, /usr/sbin/useradd, /usr/sbin/usermod
Testing Sudo Access
- name: Verify sudo access
hosts: all
become: true
tasks:
- name: Check effective user
ansible.builtin.command: whoami
register: whoami_result
changed_when: false
- name: Display effective user
ansible.builtin.debug:
msg: "Running as: {{ whoami_result.stdout }}"
Becoming a Non-Root User
You can escalate to any user, not just root:
- name: Run as application user
ansible.builtin.command: /opt/myapp/bin/start
become: true
become_user: myapp
Alternative Become Methods
Using su Instead of sudo
- hosts: all
become: true
become_method: su
become_user: root
vars:
ansible_become_password: "{{ vault_root_password }}"
Using doas (OpenBSD)
- hosts: openbsd_servers
become: true
become_method: doas
Common Mistakes
1. Missing become on Package Tasks
# ❌ Will fail
- ansible.builtin.apt:
name: nginx
state: present
# ✅ Add become
- ansible.builtin.apt:
name: nginx
state: present
become: true
2. Sudo Password Required But Not Provided
fatal: [host]: FAILED! => {"msg": "Missing sudo password"}
Fix: Either configure passwordless sudo or use --ask-become-pass:
ansible-playbook playbook.yml --ask-become-pass
3. User Not in sudoers
fatal: [host]: FAILED! => {"msg": "deploy_user is not in the sudoers file."}
Fix: Add the user to sudoers on the target:
echo "deploy_user ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers.d/deploy_user
4. become: true on Gathering Facts
If your SSH user can't read certain system info without sudo:
- hosts: all
become: true # Also affects fact gathering
gather_facts: true
5. Mixing become Levels Unexpectedly
- hosts: all
become: true # All tasks run as root
tasks:
- name: Create file owned by deploy user
ansible.builtin.file:
path: /home/deploy/app.conf
state: touch
owner: deploy
# Runs as root (from play-level become) - file is created as root then chowned
Security Best Practices
- Use
becomeonly where needed — don't set it at play level if only some tasks need it - Limit sudo permissions — use
/etc/sudoers.d/to restrict which commands can be run - Use Ansible Vault for sudo passwords if passwordless sudo is not an option
- Audit become usage — review playbooks for unnecessary privilege escalation
- Use
become_userfor application tasks — run app commands as the app user, not root - Never SSH directly as root — use a regular user with sudo instead
Related Articles
- Ansible become Privilege Escalation Guide
- Ansible Vault Guide
- Create User Account with Ansible
- Ansible Playbook Guide
Conclusion
The "This command has to be run under the root user" error means your task needs privilege escalation. The fix is adding become: true at the appropriate level — play, block, role, or task. For production environments, configure passwordless sudo for the Ansible user with minimal required permissions. Use task-level become instead of play-level when only specific tasks need root, and always follow the principle of least privilege.