Permission denied is Linux telling you the current user is not allowed to do something. The cause is almost always one of a few things, and the trick is checking the whole path, not just the file. This guide goes through them in the order worth checking.
Before you start
- Know which user gets the error: you in SSH, or a service like
www-data,nginxormysql. - Have the exact command and path that failed.
Check the whole path with namei
namei -l /var/www/site/storage/logs/app.logIt lists the owner and permissions of every directory on the way. To open a file, a user needs execute (x) on every parent directory and read (r) on the file; to create files, write (w) and x on the containing directory.
Test as the affected user:
sudo -u www-data test -r /var/www/site/index.php && echo readableRunning a script: missing execute bit
./deploy.sh
bash: ./deploy.sh: Permission deniedAdd execute permission, or run it through the interpreter:
chmod +x deploy.shbash deploy.shIf chmod +x is set and it still fails, the filesystem may be mounted noexec (common for /tmp); check with findmnt -T deploy.sh.
Wrong owner or mode
Web apps often fail to write logs, caches or uploads:
chown -R deploy:www-data /var/www/site/storage && chmod -R ug+rwX /var/www/site/storageAvoid chmod 777; give access to the right owner or group instead.
Needs root: sudo and redirects
System files need root. A classic trap is redirecting with sudo:
sudo echo 'vm.swappiness=10' > /etc/sysctl.d/99-swap.confThe redirect runs in your unprivileged shell, so it fails. Use tee:
echo 'vm.swappiness=10' | sudo tee /etc/sysctl.d/99-swap.confSSH: Permission denied (publickey)
Check ~/.ssh is 700, authorized_keys is 600, both owned by the user, and the home directory is not group- or world-writable. See the SSH troubleshooting guide for more.
SELinux (AlmaLinux, Rocky)
If normal permissions look correct on RHEL-based systems, SELinux may block the access. Check recent denials:
ausearch -m avc -ts recentTypical fixes: restore the right labels after moving files with restorecon -Rv /var/www/site, allow web content to be written with semanage fcontext -a -t httpd_sys_rw_content_t '/var/www/site/storage(/.*)?' followed by restorecon, or allow network connections from the web server with setsebool -P httpd_can_network_connect 1. Avoid disabling SELinux entirely.
AppArmor (Ubuntu)
Services like MySQL have AppArmor profiles that restrict paths. Moving the MySQL data directory triggers denials visible in journalctl -k | grep -i apparmor. Update the profile (e.g. /etc/apparmor.d/local/usr.sbin.mysqld) and reload AppArmor.
Other causes
- Immutable files:
lsattr fileshowsi; remove withchattr -i file(root). - ACLs: a
+after the mode inls -l; inspect withgetfacl. - Ports below 1024: non-root programs cannot bind to them; use a reverse proxy or a higher port.
- Read-only filesystem: a different error, but similar symptoms.
Permission denied FAQ
Why does it work with sudo but not without?
Root bypasses normal permission checks. Fix ownership so the intended user has access instead of running everything as root.
Why can my user read the file but the web server cannot?
The web server user lacks execute permission on a parent directory, often your home directory.
Does this happen on cPanel hosting?
Yes, typically from wrong file modes. Use 644 for files and 755 for folders in File Manager.
