Permission Denied Linux: Fix with chmod and chown

Fix 'permission denied' errors in Linux — read permission bits correctly, use chmod and chown safely, debug with ls -la and stat, and avoid common mistakes that break applications.

April 22, 2026·5 min read·Damon

Permission denied. Deployment failed. Service won't start. Script can't read a file. The fix is usually one of two things: wrong ownership (chown) or wrong permission bits (chmod). Here's how to diagnose and fix both.


TL;DR

# See who owns the file and what permissions it has
ls -la /path/to/file
stat /path/to/file

# Change owner
chown appuser:appgroup /path/to/file
chown -R appuser:appgroup /path/to/directory

# Change permissions
chmod 644 /path/to/file       # rw-r--r--  (file: owner rw, others r)
chmod 755 /path/to/directory  # rwxr-xr-x  (dir: owner rwx, others rx)
chmod +x /path/to/script      # add execute for everyone

Read ls -la Output

ls -la /var/log/app/
drwxr-xr-x  2 appuser appgroup 4096 Apr 22 09:15 .
drwxr-xr-x 12 root    root     4096 Apr 22 09:00 ..
-rw-r--r--  1 appuser appgroup  512 Apr 22 09:15 app.log
-rwxr-xr-x  1 root    root     1024 Apr 20 14:00 startup.sh

Breaking down -rw-r--r--:

- rw- r-- r--
│ │   │   └── others: read only
│ │   └────── group:  read only
│ └────────── owner:  read + write
└──────────── type: - = file, d = directory, l = symlink

The columns after permissions: links owner group size date name


chmod: Fix Permission Bits

Numeric (octal) mode

# Common permission sets
chmod 644 file.conf    # rw-r--r--  config files
chmod 640 secrets.env  # rw-r-----  sensitive configs (group readable)
chmod 600 private.key  # rw-------  SSH keys, secrets
chmod 755 script.sh    # rwxr-xr-x  executables, directories
chmod 750 /opt/app     # rwxr-x---  app dir (group access, others none)
chmod 700 /root/.ssh   # rwx------  highly sensitive dirs

Octet math: r=4, w=2, x=1. Add them: rw- = 4+2+0 = 6, r-x = 4+0+1 = 5.

Symbolic mode (easier to read)

chmod +x script.sh          # add execute for all
chmod u+x,g-w file          # add execute for owner, remove write for group
chmod o-rwx sensitive.conf  # remove all permissions for others
chmod a=r public.txt        # set read-only for everyone

Recursive (be careful)

# Fix directory tree
chmod -R 755 /opt/app

# BETTER: different permissions for files vs directories
find /opt/app -type d -exec chmod 755 {} \;
find /opt/app -type f -exec chmod 644 {} \;
find /opt/app/bin -type f -exec chmod 755 {} \;  # executables only

Never chmod -R 777 in production. It gives every user write access to every file.


chown: Fix Ownership

# Change owner
chown appuser /var/log/app/app.log

# Change owner AND group
chown appuser:appgroup /var/log/app/

# Recursive
chown -R appuser:appgroup /var/log/app/

# Change group only
chown :appgroup /var/log/app/
# or
chgrp appgroup /var/log/app/

Real Examples

Service can't write to log directory

journalctl -u myapp | grep "permission denied"
# open /var/log/myapp/app.log: permission denied

ls -la /var/log/myapp/
# drwxr-xr-x 2 root root 4096 Apr 22 09:00 myapp

# Check which user the service runs as
systemctl cat myapp | grep User
# User=appuser

# Fix: give appuser ownership
chown -R appuser:appuser /var/log/myapp
systemctl restart myapp

Script won't execute

./deploy.sh
# bash: ./deploy.sh: Permission denied

ls -la deploy.sh
# -rw-r--r-- 1 damon damon 1024 Apr 22 ...
# No execute bit!

chmod +x deploy.sh
./deploy.sh

SSH key too permissive

ssh -i ~/.ssh/mykey user@server
# WARNING: UNPROTECTED PRIVATE KEY FILE!
# Permissions 0644 for '/home/damon/.ssh/mykey' are too open.

chmod 600 ~/.ssh/mykey
chmod 700 ~/.ssh/
ssh -i ~/.ssh/mykey user@server   # now works

Nginx can't read static files

# nginx error log:
# (13: Permission denied) while reading file "/var/www/html/index.html"

ls -la /var/www/html/
# -rw------- 1 root root 1024 Apr 22 ...
# nginx user (www-data) can't read root-owned files

chown -R www-data:www-data /var/www/html/
# or keep root ownership but allow others to read:
chmod -R o+r /var/www/html/

Diagnose with stat

stat gives more detail than ls:

stat /etc/app/config.yml
  File: /etc/app/config.yml
  Size: 1024
Access: (0640/-rw-r-----)  Uid: (1001/appuser)  Gid: (1002/appgroup)

The (0640/-rw-r-----) shows octal and symbolic mode together. Immediately clear what the permissions are.


Common Mistakes

chmod -R 777 to "fix" permissions — gives write access to everyone on the system. Never do this on files a service reads. Use the minimum permissions needed.

Fixing permissions but not ownershipchmod 755 on a file owned by root doesn't help an app running as appuser. Fix chown first, then chmod.

Not checking directory execute bits — to access a file, you need execute (x) on every directory in the path, not just the file itself.

# Check full path permissions
namei -l /var/log/app/app.log
# Shows permissions of each component in the path

Fixing the file but forgetting new files — if the app creates new log files, those inherit the directory's umask, not your manual fix. Set the directory's sticky group bit:

chmod g+s /var/log/myapp   # new files inherit group from directory

Special Bits

# Setuid (s) — run as file owner, not caller
chmod u+s /usr/bin/passwd

# Setgid (s) on directory — new files inherit directory group
chmod g+s /shared/project/

# Sticky bit (t) — only owner can delete files (used on /tmp)
chmod +t /shared/uploads/

Conclusion

ls -la first — confirm who owns the file and what the permissions are. stat for more detail. chown to fix ownership, chmod to fix permissions. Always set the minimum permissions needed. chmod -R 777 is never the right answer.


Related: CIS Level 1 Ubuntu Hardening — file permission hardening in production. Linux Find File by Name and Sizefind -perm to audit permissions across a directory tree.