Linux File Permissions Explained: chmod, chown, and ACLs

✅ Applies to all Linux distributions · Last updated: June 2026
Linux file permissions control who can read, write, and execute every file and directory on the system. Understanding permissions is essential for security, web server configuration, running scripts, and avoiding the dreaded "Permission denied" error. This guide covers everything: the permission model, chmod, chown, chgrp, special permissions, and Access Control Lists (ACLs).
Practicing this on a live server, or need one to follow along? See our comparison of the best Linux VPS hosting providers for 2026 if you need a Linux box to work on.
- The Linux Permission Model
- Reading Permission Output
- chmod: Change Permissions
- chown: Change File Ownership
- chgrp: Change Group
- umask: Default Permissions
- Special Permissions: setuid, setgid, sticky bit
- Access Control Lists (ACLs)
- Common Permission Scenarios
- Troubleshooting Permission Errors
- Frequently Asked Questions
The Linux Permission Model
Linux permissions are based on three concepts:
- Owner (user): The user who owns the file
- Group: A group of users who share access
- Others: Everyone else on the system
Each of these three can have three types of permissions:
- Read (r = 4): View file contents; list directory contents
- Write (w = 2): Modify file; create/delete files in directory
- Execute (x = 1): Run as a program; enter a directory (cd into it)
Reading Permission Output
$ ls -la
-rwxr-xr-x 1 jm jm 4096 Jun 08 10:30 script.sh
drwxr-x--- 2 www-data www-data 4096 Jun 08 /var/www/html
-rw-r--r-- 1 root root 2048 Jun 01 /etc/hosts
lrwxrwxrwx 1 root root 7 Apr 01 /bin -> usr/binBreaking down -rwxr-xr-x:
- rwx r-x r-x
│ │ │ │
│ │ │ └── Others: read + execute (no write)
│ │ └─────── Group: read + execute (no write)
│ └──────────── Owner: read + write + execute
└──────────────── File type: - (regular), d (directory), l (link)
# Number fields:
# 1 = number of hard links
# jm = owner
# jm = group
# 4096 = file size in bytes
# Jun 08 = modification date
# script.sh = filenamePermission in Octal (Numbers)
# Each permission set is a 3-bit number:
# r = 4, w = 2, x = 1
# rwx = 4+2+1 = 7
# rw- = 4+2+0 = 6
# r-x = 4+0+1 = 5
# r-- = 4+0+0 = 4
# -wx = 0+2+1 = 3
# -w- = 0+2+0 = 2
# --x = 0+0+1 = 1
# --- = 0+0+0 = 0
# So rwxr-xr-x = 7 5 5 = 755
# rw-r--r-- = 6 4 4 = 644
# rwx------ = 7 0 0 = 700
# rw------- = 6 0 0 = 600chmod: Change Permissions
Numeric (Octal) Mode
chmod 644 file.txt # rw-r--r-- (standard file)
chmod 755 script.sh # rwxr-xr-x (executable)
chmod 700 private.sh # rwx------ (owner only)
chmod 600 ~/.ssh/id_ed25519 # rw------- (private key)
chmod 755 /var/www/html/ # rwxr-xr-x (web directory)
chmod 777 file.txt # rwxrwxrwx (everyone can do anything - usually bad)
# Recursive (apply to directory and all contents):
chmod -R 755 /var/www/html/
chmod -R 600 ~/.ssh/Symbolic Mode
# Syntax: [who][operator][permissions]
# who: u (user/owner), g (group), o (others), a (all)
# operator: + (add), - (remove), = (set exactly)
# permissions: r, w, x
chmod +x script.sh # add execute for everyone
chmod u+x script.sh # add execute for owner only
chmod go-w file.txt # remove write from group and others
chmod a+r file.txt # add read for everyone
chmod u=rwx,go=rx file.txt # set owner=rwx, group+others=rx (same as 755)
chmod g+s directory/ # add setgid bit to directory
chmod o-rwx secret.txt # remove all permissions from othersCommon Permission Patterns
| Permission | Octal | Use Case |
|---|---|---|
| rw-r--r-- | 644 | Normal files (readable by all, writable by owner) |
| rwxr-xr-x | 755 | Scripts, directories, executables |
| rw------- | 600 | SSH keys, private config files |
| rwx------ | 700 | Private scripts and directories |
| rw-rw-r-- | 664 | Shared files (group can write) |
| rwxrwxr-x | 775 | Shared directories |
| rwxrwxrwx | 777 | Avoid, security risk |
chown: Change File Ownership
# Change owner:
sudo chown jm file.txt # change owner to jm
# Change owner and group:
sudo chown jm:jm file.txt # owner=jm, group=jm
sudo chown www-data:www-data /var/www/html # web server
# Change group only (keep owner):
sudo chown :www-data file.txt
# Recursive:
sudo chown -R jm:jm /home/jm/projects/
sudo chown -R www-data:www-data /var/www/html/
# Change owner to match another file:
sudo chown --reference=reference_file target_file
# Change ownership for all files in directory (using find for more control):
find /var/www -type f -exec chown www-data:www-data {} ;
find /var/www -type d -exec chmod 755 {} ; # directories
find /var/www -type f -exec chmod 644 {} ; # fileschgrp: Change Group
sudo chgrp www-data file.txt # change group
sudo chgrp -R developers /opt/app/ # recursive
# View a user's groups:
groups jm
id jm
# Add user to group:
sudo usermod -aG www-data jm # add jm to www-data group
# Log out and back in for group change to take effect
# Create a new group:
sudo groupadd developers
sudo usermod -aG developers jmumask: Default Permissions
The umask defines what permissions are removed from newly created files and directories. Default umask is usually 022:
# View current umask:
umask
# 0022
# How umask works:
# Default file: 666 (rw-rw-rw-)
# Default dir: 777 (rwxrwxrwx)
# umask 022 removes: ----w--w-
# Result files: 644 (rw-r--r--)
# Result dirs: 755 (rwxr-xr-x)
# Change umask for current session:
umask 027 # files: 640, dirs: 750 (group can read, others nothing)
umask 077 # files: 600, dirs: 700 (owner only - maximum privacy)
# Make permanent - add to ~/.bashrc:
echo 'umask 022' >> ~/.bashrcSpecial Permissions: setuid, setgid, sticky bit
setuid (SUID): Run as Owner
When set on an executable, it runs with the permissions of the file owner (not the user running it). Used for programs that need root privileges temporarily (like passwd).
# Example: /usr/bin/passwd has setuid:
ls -la /usr/bin/passwd
# -rwsr-xr-x 1 root root 59976 ... /usr/bin/passwd
# Note the 's' in place of 'x' for owner - that's setuid
# Set setuid:
chmod u+s /usr/bin/myapp # symbolic
chmod 4755 /usr/bin/myapp # numeric (4 prefix = setuid)
# SECURITY WARNING: setuid programs are major security risks.
# If a setuid-root program has a vulnerability, attackers can get root.
# Never set setuid on scripts (bash ignores it for security).setgid (SGID): Group Inheritance
On directories: files created inside inherit the directory's group instead of the creator's primary group. Very useful for shared project directories.
# Create a shared project directory:
sudo mkdir /opt/team-project
sudo chown :developers /opt/team-project
sudo chmod 2775 /opt/team-project # 2 prefix = setgid
# or: chmod g+s /opt/team-project
ls -la /opt/
# drwxrwsr-x 2 root developers ... team-project
# Note the 's' in group position
# Now any file created in team-project automatically belongs to developers group
# regardless of which developer creates itSticky Bit: Protect Directory Contents
When set on a directory, only the file owner (or root) can delete or rename files in it, even if others have write permission. Used on /tmp to prevent users from deleting each other's files.
# /tmp has sticky bit:
ls -la / | grep tmp
# drwxrwxrwt 12 root root ... tmp
# Note the 't' at the end = sticky bit
# Set sticky bit:
chmod +t /shared/uploads/ # symbolic
chmod 1777 /shared/uploads/ # numeric (1 prefix = sticky)
# Practical use: shared upload directory where users can't delete each other's files
sudo mkdir /var/shared
sudo chmod 1777 /var/sharedAccess Control Lists (ACLs)
Standard Linux permissions only have owner/group/others. ACLs extend this to allow specific users or groups to have different permissions on a file.
# Install ACL tools:
sudo apt install acl -y
# View ACLs:
getfacl /var/www/html/
# Give specific user read/write access:
sudo setfacl -m u:john:rw /var/www/html/config.php
# Give specific group execute access:
sudo setfacl -m g:developers:rx /opt/deploy.sh
# Set default ACL for new files in a directory:
sudo setfacl -d -m u:john:rw /var/www/html/
# Remove ACL entry:
sudo setfacl -x u:john /var/www/html/config.php
# Remove all ACLs:
sudo setfacl -b /var/www/html/config.php
# Check if ACLs are active (look for '+' after permissions):
ls -la /var/www/html/config.php
# -rw-rw-r--+ 1 www-data www-data 1234 ... config.php
# ^ the '+' indicates ACLs are setCommon Permission Scenarios
Set Up a Web Server Directory
# Standard web server permissions:
sudo chown -R www-data:www-data /var/www/html/
sudo find /var/www/html -type d -exec chmod 755 {} ;
sudo find /var/www/html -type f -exec chmod 644 {} ;
# Allow your user to edit web files without sudo:
sudo usermod -aG www-data $USER
sudo chmod g+w /var/www/html # or use setgidMake a Script Executable
chmod +x myscript.sh
./myscript.sh
# Make accessible system-wide:
sudo cp myscript.sh /usr/local/bin/myscript
sudo chmod 755 /usr/local/bin/myscriptFix Broken Permissions on Home Directory
# If permissions got messed up in home directory:
chmod 755 ~
chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys
chmod 600 ~/.ssh/id_ed25519
chmod 644 ~/.ssh/id_ed25519.pub
# Fix home directory ownership:
sudo chown -R $USER:$USER ~Troubleshooting Permission Errors
Permission denied running a script
# Script doesn't have execute bit:
chmod +x script.sh
# If script is on a noexec-mounted filesystem:
mount | grep noexec # check for noexec mounts
# Run directly with bash instead:
bash script.shWeb server can't read files
# Check who runs the web server:
ps aux | grep nginx | grep -v grep
# www-data 1234 ... nginx: worker process
# Check file permissions:
ls -la /var/www/html/index.php
# Fix: web server needs at least read (r) permission, directories need x:
sudo chown www-data:www-data /var/www/html/index.php
sudo chmod 644 /var/www/html/index.phpSSH key rejected: "bad permissions"
# SSH is strict about key file permissions:
chmod 700 ~/.ssh
chmod 600 ~/.ssh/id_ed25519
chmod 644 ~/.ssh/id_ed25519.pub
chmod 600 ~/.ssh/authorized_keys
chmod 644 ~/.ssh/known_hosts
chmod 644 ~/.ssh/configFrequently Asked Questions
Why is 777 a bad idea?
777 means any user on the system can read, write, and execute the file. On a shared server, that means any compromised web application can modify your files. For web servers, if an attacker exploits a vulnerability, they can overwrite 777 files with malicious code. Use the minimum permissions needed: 644 for files, 755 for directories.
What's the difference between 666 and 644?
Both give the owner read+write access. 666 also gives group and others write access (rw-rw-rw-): anyone can modify the file. 644 only gives group and others read access (rw-r--r--): others can read but not write. Default file creation with umask 022 gives 644.
Can I change permissions on files I don't own?
No (unless you're root). Only the file owner or root can change permissions with chmod or ownership with chown. If you need access to another user's files, ask root to adjust ownership or group membership, or use ACLs.
Understanding permissions is fundamental to Linux security and administration. Once you're comfortable with this, check out our guide on setting up SSH where permissions play a critical role in key-based authentication.
Further Reading

JM Carreira
I’ve used Linux since 2008 and it has been my main system since 2021. When an article has a “Tested on” box, I ran the steps on my Lenovo Tiny. More about me and the test machine.
