How to Fix "Operation Not Permitted" Errors in Linux

You run a command, and Linux throws back "Operation not permitted" — even though you're root, even though the file exists, even though everything looks fine. This error is one of the more frustrating ones precisely because it doesn't tell you why. The fix depends entirely on the cause, and there are at least six distinct causes worth checking.

What "Operation Not Permitted" Actually Means

This error maps to EPERM (errno 1) in the Linux kernel — a signal that the kernel itself blocked the operation, independent of file permissions. That distinction matters more than most guides acknowledge.

Many users confuse it with EACCES (errno 13), which shows up as "Permission denied." The difference is meaningful: EACCES means the filesystem permission check failed — wrong user, wrong group, wrong mode bits. EPERM means the kernel refused the syscall at a deeper level. You can have full read/write permissions on a file and still hit EPERM if an immutable flag, a MAC policy, or a capability restriction is in play.

Knowing this upfront saves you from chasing the wrong fix. If chmod and chown don't resolve it, you're dealing with something the filesystem permission model doesn't control.

Common Causes at a Glance

Before diving into each fix, here's a quick-reference list of the six most frequent root causes. Match your situation to one of these, then jump to the relevant section.

  • Wrong file ownership or permission bits — the most common cause; fixable with chown and chmod
  • Immutable file attribute — set via chattr +i; invisible to ls -l but blocks all writes even for root
  • SELinux or AppArmor policy — mandatory access control denies the operation regardless of Unix permissions
  • Mount options — filesystem mounted with noexec, nosuid, or read-only prevents certain operations
  • Missing Linux capabilities — the process lacks a specific capability (e.g., CAP_NET_ADMIN) needed for the syscall
  • Container or namespace restrictions — Docker, LXC, or a user namespace limits what the process can do at the kernel level

Check File Ownership and Permissions First

Start here. Ownership and permission mismatches are the most common cause, and they're the fastest to rule out.

Run ls -l /path/to/file to see the current owner, group, and mode bits. For more detail, stat /path/to/file shows the numeric UID/GID alongside the octal permissions. Compare the file's owner against the UID of the process trying to access it — a mismatch is your answer.

To fix ownership:

sudo chown youruser:yourgroup /path/to/file

To fix permissions (use the minimum necessary — avoid the chmod 777 reflex):

sudo chmod 644 /path/to/file   # read/write for owner, read-only for others
sudo chmod 755 /path/to/dir    # executable directories need the execute bit

If the file is owned by root and you're running as a regular user, either run the command with sudo or change ownership to your user. Don't default to running everything as root — that trades one problem for a larger one.

Immutable Flags and Extended Attributes

If permissions look correct but the error persists, check for an immutable flag. This is a frequently overlooked cause because ls -l doesn't show it.

The chattr +i command marks a file immutable at the filesystem level. Even root cannot modify, delete, or rename it until the flag is removed. To check:

lsattr /path/to/file

If the output shows ----i-----------, the immutable bit is set. Remove it with:

sudo chattr -i /path/to/file

Then retry your original command. This fix resolves a surprising number of "why can't root write to this file" situations, especially on systems where administrators have locked down configuration files intentionally.

Worth noting: some system files are made immutable on purpose. Before removing the flag, confirm you actually need to modify that file.

SELinux and AppArmor Restrictions

Mandatory access control (MAC) systems like SELinux and AppArmor operate above the standard Unix permission layer. They can block operations for root itself, which is exactly the point — they're designed to contain damage from compromised processes.

On SELinux systems (common on RHEL, Fedora, CentOS), check the audit log for denials:

sudo ausearch -m avc -ts recent
# or
sudo grep "denied" /var/log/audit/audit.log | tail -20

For AppArmor (Ubuntu, Debian), check:

sudo dmesg | grep -i apparmor
sudo cat /var/log/syslog | grep apparmor

For diagnosis, you can temporarily set SELinux to permissive mode — it logs denials without enforcing them:

sudo setenforce 0   # temporary, reverts on reboot

If the error disappears in permissive mode, SELinux is the cause. The right fix is to create a targeted policy rule, not to leave SELinux disabled. Use audit2allow to generate a policy module from the audit log:

sudo ausearch -m avc -ts recent | audit2allow -M mypolicy
sudo semodule -i mypolicy.pp

For AppArmor, you can set a specific profile to complain mode: sudo aa-complain /path/to/binary. This logs violations without blocking them, letting you identify what the profile needs to allow.

Mount Options and Read-Only Filesystems

A filesystem mounted with restrictive options will return EPERM for operations those options prohibit — even if permissions and ownership are correct.

Check current mount options:

mount | grep /path/to/mountpoint
# or for more detail:
cat /proc/mounts

Three mount options commonly cause this error:

  • ro (read-only) — no writes permitted; common on live systems, recovery environments, or misconfigured fstab entries
  • noexec — prevents executing binaries from that filesystem; scripts and compiled binaries both fail
  • nosuid — blocks setuid/setgid execution; affects programs that rely on privilege escalation

To remount a filesystem with different options temporarily:

sudo mount -o remount,rw /mountpoint

For a permanent fix, edit /etc/fstab and remove or change the relevant option, then remount. Be careful with noexec on /tmp — some installers and scripts write executables there and will break if you add it without accounting for that.

Container and Namespace Limitations

Inside a Docker or LXC container, "Operation not permitted" often means the host kernel is blocking a privileged syscall that the container's process doesn't have the capability to make.

Containers run with a reduced set of Linux capabilities by default. Operations like modifying network interfaces, loading kernel modules, or changing system time require capabilities (CAP_NET_ADMIN, CAP_SYS_MODULE, CAP_SYS_TIME) that Docker drops unless you explicitly grant them.

To check what capabilities a running process has:

cat /proc/self/status | grep Cap
capsh --decode=<hex value>

To add a specific capability when running a Docker container:

docker run --cap-add NET_ADMIN myimage

The --privileged flag grants all capabilities and disables seccomp filtering — it fixes the error, but it also removes most of the security isolation the container provides. Use it only for debugging, then switch to targeted --cap-add flags for production.

For getcap and setcap on binaries outside containers:

getcap /usr/bin/ping          # check current capabilities
sudo setcap cap_net_raw+ep /usr/bin/ping  # grant specific capability

This approach — granting a specific capability to a specific binary — is almost always preferable to running the whole process as root.

Frequently Asked Questions

Why do I get "Operation not permitted" even when running as root?

Root bypasses standard Unix permission checks, but not everything. Immutable file attributes, SELinux/AppArmor policies, and container capability restrictions all operate independently of the root UID. Check lsattr for immutable flags and your MAC audit logs for policy denials.

What is the difference between "Operation not permitted" and "Permission denied"?

"Permission denied" (EACCES) means the filesystem permission check failed — wrong user, group, or mode bits. "Operation not permitted" (EPERM) means the kernel rejected the syscall at a deeper level, often due to capabilities, MAC policies, or filesystem flags. The fix path is different for each.

How do I find which process or rule is blocking my command?

Run the command with strace to see the exact syscall that fails: strace -e trace=all yourcommand 2>&1 | grep EPERM. For MAC-related blocks, check /var/log/audit/audit.log (SELinux) or dmesg | grep apparmor.

Can I fix this error without disabling SELinux or AppArmor entirely?

Yes. Use audit2allow to generate a targeted SELinux policy from the denial log, or use aa-complain to identify what AppArmor needs to permit. Disabling MAC entirely trades a specific fix for a broad security regression.

Why does this error appear inside a Docker container?

Docker drops most Linux capabilities by default and applies a seccomp filter that blocks certain syscalls. The container process hits EPERM when it attempts an operation requiring a capability it wasn't granted. Add the specific capability with --cap-add rather than using --privileged.

{{HOMEPAGE_LINKS}}