You type a command, press Enter, and Linux answers with two words every user meets sooner or later: Permission denied. It can appear when you run a script, edit a config file, mount a drive, log in over SSH, or start a container.
The error is never random. Some layer of the Linux security model said no, and your job is to find which one. This guide shows How to Fix Permission Denied Errors in Linux by diagnosing the cause first, instead of reaching for chmod 777 and hoping.
The steps cover Ubuntu, Debian 13, Fedora, RHEL 10 and its rebuilds (Rocky, AlmaLinux), Arch, and openSUSE. Where distros behave differently, I say so.
Why Linux Says “Permission Denied”
Before a process touches a file, Linux checks several layers, roughly in this order:
- Standard permissions: owner, group and others, each with read, write and execute.
- Directory traversal: you need execute (
x) on every folder in the path. - ACLs: extra per-user or per-group rules.
- Attributes and mount options: immutable flag, read-only mount,
noexec. - Mandatory access control: SELinux or AppArmor.
- Service sandboxing: systemd restrictions and containers.
Most guides stop at layer 1. The stubborn cases usually live in layers 2 to 6, so work through them in order.
Step 1: Read the Error Message Closely
The exact wording tells you where to look.
bash: ./script.sh: Permission deniedmeans the file isn’t executable, or sits on anoexecmount.cat: /etc/shadow: Permission deniedmeans you need elevated rights.mkdir: cannot create directory: Permission deniedpoints at the parent directory.Permission denied (publickey)is an SSH authentication problem, not a file problem.Operation not permittedis a different error. It usually means an immutable flag, a missing capability, or a root-only action.
Note the full path and the command before you change anything.
Step 2: Check Ownership and Permissions
ls -l /path/to/file
id
Sample output:
-rw-r----- 1 root adm 4821 Oct 18 09:12 app.log
Read it like this: owner root can read and write, group adm can read, everyone else gets nothing. If your id output doesn’t list adm, you can’t open this file.
Check the whole path
People skip this, and it’s behind a lot of confusing cases. If you can’t enter a parent folder, the file’s own permissions are irrelevant. namei shows every component:
namei -l /var/www/site/uploads/photo.jpg
The directory that blocks you stands out immediately.
Reading the permission numbers
| Octal | Symbolic | Meaning |
|---|---|---|
| 7 | rwx | read, write, execute |
| 6 | rw- | read, write |
| 5 | r-x | read, execute |
| 4 | r– | read only |
| 0 | — | no access |
On a directory, x means “allowed to enter.” Without it you can’t cd in or reach anything inside, even with r. The Linux man-pages entry for chmod documents the full syntax, including the special setuid, setgid and sticky bits.
Step 3: Fix It with chmod
If the mode bits are wrong for the job, change them.
chmod +x script.sh # make a script executable
chmod 644 file.txt # owner read/write, others read
chmod 755 mydir/ # owner full, others enter and read
chmod 600 secret.key # owner only
To fix a whole project tree without marking every text file executable:
find /path/to/project -type d -exec chmod 755 {} +
find /path/to/project -type f -exec chmod 644 {} +
A blanket chmod -R 755 makes all your files executable, which is messy and confuses some tools. The two find commands avoid that.
Why chmod 777 is a bad habit
chmod 777 “works” because it lets everyone do everything, including any other local user or a compromised service. When a tutorial recommends it, the author usually never found the real cause. A specific owner, group or ACL is almost always the better answer.
Step 4: Fix It with chown and Groups
If the mode bits are fine but the wrong account owns the file:
sudo chown youruser:yourgroup file.txt
sudo chown -R www-data:www-data /var/www/site
Web server account names differ by distro:
| Distro family | Typical web server user |
|---|---|
| Debian, Ubuntu | www-data |
| RHEL, Fedora, openSUSE (Apache) | apache |
| RHEL, Fedora (nginx) | nginx |
| Arch (Apache) | http |
Join the right group instead
Often group membership is cleaner than changing ownership:
sudo usermod -aG groupname youruser
Keep the -a. Without it, you replace all your supplementary groups, which can remove your sudo access.
Group changes don’t reach sessions that are already open. Log out and back in, or start a shell with the group:
newgrp groupname
Common real-world cases:
- Serial devices like
/dev/ttyUSB0needdialouton Debian and Ubuntu, anduucpon Arch. - The Docker socket needs the
dockergroup, which is effectively root-equivalent. Add only trusted users, or use rootless Docker or Podman. - System logs without sudo usually mean joining
adm(Debian, Ubuntu) orsystemd-journal.
Step 5: Use sudo Correctly
If the task truly needs admin rights, sudo is the right tool. Watch for these traps.
Redirection runs before sudo
This fails:
sudo echo "setting=1" > /etc/myapp.conf
Your own shell opens the file before sudo starts. Use tee instead:
echo "setting=1" | sudo tee /etc/myapp.conf
Add -a to append rather than overwrite.
Your account may not be allowed to use sudo
| Distro | Admin group |
|---|---|
| Ubuntu, Linux Mint, Debian | sudo |
| Fedora, RHEL family, Arch, openSUSE | wheel |
On Debian, setting a root password during install can leave your user without sudo. Run su -, then usermod -aG sudo youruser. On Arch, installing sudo isn’t enough. Run visudo and uncomment the %wheel line.
For protected files, prefer sudoedit over opening an editor as root. It edits a copy as you and writes it back with privileges.
Step 6: Check ACLs
If ls -l looks fine but access still behaves oddly, look for a + at the end of the permission string, such as -rw-r--r--+. That marks an ACL.
getfacl file.txt
setfacl -m u:alice:rw file.txt
setfacl -R -m u:alice:rwX /srv/shared
For a shared folder where new files should inherit access, add a default ACL:
setfacl -d -m g:devs:rwX /srv/shared
ACLs work on ext4, XFS and Btrfs with default mount options on current distros. They beat widening “others” permissions.
Step 7: Check Attributes and Mount Options
Immutable files
If even root gets “Operation not permitted”:
lsattr file.txt
sudo chattr -i file.txt
An i in the lsattr output means the file is immutable, and chattr -i clears it.
Read-only and noexec mounts
If scripts won’t run from a USB drive, or writes fail on a mounted disk:
findmnt -T /path/to/file
sudo mount -o remount,rw /mnt/data
Look for ro or noexec in the options. For a permanent change, edit /etc/fstab carefully and test with sudo mount -a before rebooting. A disk can also flip to read-only after filesystem errors, so check dmesg before blindly remounting.
FAT, exFAT and NTFS drives
These filesystems don’t store Unix permissions, so chmod and chown do nothing useful. Ownership is set at mount time with the uid=, gid= and umask= options.
Step 8: Check SELinux
This is the classic “everything looks right and it still fails” case. SELinux is enforcing by default on Fedora and the RHEL family. It’s also the default on new installs of openSUSE Leap 16 and Tumbleweed, a change from the AppArmor default in Leap 15.x. Upgraded Leap systems can keep AppArmor.
getenforce
sudo ausearch -m avc -ts recent
If setroubleshoot-server is installed, sudo journalctl -t setroubleshoot prints plain-English suggestions. Fedora’s guide on troubleshooting problems related to SELinux notes that labeling mistakes are the most common cause, so check labels before touching policy.
Fix the label first
Files moved with mv keep their old label. Restore the correct one:
sudo restorecon -Rv /var/www/html
Custom directories
If a service legitimately uses a non-standard path, define the rule and apply it:
sudo semanage fcontext -a -t httpd_sys_content_t "/srv/mysite(/.*)?"
sudo restorecon -Rv /srv/mysite
Booleans
getsebool -a | grep httpd
sudo setsebool -P httpd_can_network_connect on
Test, don’t disable
sudo setenforce 0 is a fine diagnostic. If the error disappears, SELinux was the cause. Switch back with setenforce 1 and fix the label or boolean. Turning SELinux off permanently removes a real protection layer.
Step 9: Check AppArmor
Ubuntu and Debian ship AppArmor enabled, and so do openSUSE Leap 15.x and upgraded systems that kept it. A confined program can be blocked from a path even when Unix permissions allow access.
sudo aa-status
sudo journalctl -k | grep -i apparmor
Look for apparmor="DENIED" lines naming the profile and path. Typical fixes:
- Add a rule to the local override file under
/etc/apparmor.d/local/for that profile. - Reload it with
sudo apparmor_parser -r /etc/apparmor.d/profile.name. - To test, put one profile in complain mode with
sudo aa-complain /path/to/binary, then restore it withaa-enforce.
A common example is MariaDB failing after you move its data directory. The profile only allows the default location, so the new path has to be added. Ubuntu’s official AppArmor documentation covers profile modes, reloading and customization.
Step 10: Check systemd Sandboxing and Containers
Service hardening
A service can run as the right user and still be blocked by its unit file. Options like ProtectHome=, ProtectSystem= and PrivateTmp= restrict what it can see. The systemd.exec documentation explains each one. Inspect the unit:
systemctl cat myservice
Then grant a specific writable path with a drop-in:
sudo systemctl edit myservice
[Service]
ReadWritePaths=/srv/data
Finish with sudo systemctl restart myservice.
Docker and Podman volumes
Bind mounts fail for two reasons: the container’s user ID doesn’t match the host file owner, or SELinux blocks access. For the second, add a relabel flag:
docker run -v /srv/data:/data:Z image
Use :z for a volume shared between containers and :Z for a private one. Never apply these to system directories such as /home or /etc.
Step 11: SSH “Permission denied (publickey)”
This looks like a file problem but usually isn’t. First, tighten permissions:
chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys
chmod 600 ~/.ssh/id_ed25519
Your home directory also shouldn’t be group-writable, because OpenSSH’s strict checks reject it. Run ssh -v user@host to see which key was offered and why it failed.
One more case: on a fresh openSUSE Leap 16 install, sshd accepts key-based login only and password login is off by default. If you never set up keys, you’ll see this exact error.
Quick Diagnostic Table
| Symptom | Likely cause | First command |
|---|---|---|
| Script won’t run | Missing execute bit or noexec mount | ls -l, findmnt -T |
Can’t edit a file in /etc | Needs root | sudoedit file |
| Fails deep in a folder tree | Missing x on a parent | namei -l path |
| Works as root, fails as a service | SELinux, AppArmor or systemd sandbox | ausearch, journalctl -k, systemctl cat |
| Root is denied too | Immutable flag or read-only mount | lsattr, findmnt |
Access breaks after mv | Wrong SELinux label | ls -Z, restorecon |
| New group has no effect | Session not refreshed | id, then log in again |
Comparing the Fix Methods
| Method | Scope | Risk if misused | Best for |
|---|---|---|---|
chmod | One file or tree | Over-granting access | Wrong mode bits |
chown | One file or tree | Locking out other users | Wrong owner |
| Group membership | Everything the group can reach | Over-broad access (e.g. docker) | Shared folders, devices |
| ACLs | Named users or groups | Hard to audit at a glance | One-off extra access |
sudo | A single command | Root-owned files left behind | True admin tasks |
| SELinux or AppArmor edits | A single confined service | Weakened policy if rushed | Confined services |
A simple rule: fix the narrowest layer that solves the problem. If a group works, don’t touch “others.” If a label fix works, don’t disable the policy.
Pros and Cons of the Main Approaches
chmod
- Pros: instant, built into every distro, easy to reverse.
- Cons: only fixes the mode bits, so it does nothing for SELinux or mount problems.
ACLs
- Pros: grant access to one person without changing ownership.
- Cons: the
+flag is easy to overlook, so they get forgotten during audits.
Group membership
- Pros: one change covers many files and survives new file creation.
- Cons: needs a fresh login, and some groups carry far more power than they seem.
Fixing SELinux or AppArmor properly
- Pros: the service works while protection stays on.
- Cons: a steeper learning curve than flipping a switch.
Mistakes That Make Things Worse
- Running everything with sudo. Root-owned files in your home folder cause new errors later. Repair with
sudo chown -R $USER:$USER ~/folder. - Recursive changes on system paths.
chmod -Rorchown -Ron/,/etc,/usror/varcan break the system. Check the path twice. - Ignoring umask. New files get default modes from
umask. Runumaskto check;022is typical and077makes private files. - Skipping setgid on shared folders.
chmod g+s /srv/sharedmakes new files inherit the folder’s group.
A Worked Example
Say Nginx returns 403 after you move a site to /srv/site on a Fedora server.
namei -l /srv/site/index.htmlshows every permission is fine.getenforcereturnsEnforcing.ausearch -m avc -ts recentshows a denial against thedefault_tlabel.semanage fcontextplusrestorecon -Rv /srv/sitefixes it.
No chmod was needed. Checking the path first, then the policy layer, solves a large share of “mystery” errors.
FAQ
What does “Permission denied” mean in Linux?
Your user or process lacks the required rights, or a layer such as SELinux, AppArmor or a mount option blocked the action.
How do I fix “Permission denied” when running a script?
Run chmod +x script.sh and try again; if it still fails, check whether the filesystem is mounted noexec.
Is chmod 777 safe?
No, because it lets any user modify the file, so use a specific owner, group or ACL instead.
Why do I get “Permission denied” even as root?
Root is still blocked by immutable flags, read-only mounts and SELinux or AppArmor rules, which you can check with lsattr, findmnt and the audit logs.
Why isn’t my new group membership working?
Group changes apply only to new login sessions, so log out and back in or run newgrp groupname.
How do I fix “Permission denied (publickey)” on SSH?
Set ~/.ssh to 700 and your private key and authorized_keys to 600, then run ssh -v to see which key is being offered.
Conclusion
Permission errors are frustrating, but they follow a clear logic. Check ownership and the full directory path, then groups and ACLs, then mount options, SELinux or AppArmor, and finally service sandboxing. Fix the layer that is actually blocking you instead of loosening everything.
That is How to Fix Permission Denied Errors in Linux on any major distro: diagnose first, change as little as possible, and keep your security tools switched on. Bookmark the diagnostic table above, because it will save you time the next time those two words appear.
Disclaimer: This guide is for general informational purposes. Commands that change permissions, ownership, mounts or security policies can affect system stability and security. Test on a non-critical system first, keep backups, and check your distribution’s official documentation for release-specific behavior.
More Linux Troubleshooting Guides
Fix common Linux problems with these practical troubleshooting tutorials.
Troubleshoot broken packages, update errors, and Linux systems that stop working after an upgrade.
Learn how to diagnose file manager crashes, launch failures, and problems accessing files and folders.
Resolve display detection issues, check graphics drivers, and troubleshoot external monitor connections.
More Linux tips and tutorials at Techrefreshing.com.
