Linux file permissions form the bedrock of system security. Every file and directory on a Linux system has an associated set of permissions that determines who can read, write, or execute it. Whether you are a system administrator securing production servers, a developer deploying web applications, or a DevOps engineer automating infrastructure, understanding permissions is absolutely essential. Misconfigured permissions are among the top causes of security breaches, data loss, and deployment failures in Linux environments.
In this comprehensive guide, we break down every aspect of the Linux permission system — from the basic rwx model and octal notation to advanced features like ACLs, special permission bits, and SELinux contexts. By the end of this article, you will have the deep knowledge needed to configure file permissions correctly, troubleshoot access issues efficiently, and harden your servers against permission-based attacks.
Understanding the Linux Permission Model
The Linux permission system is built on a simple but powerful three-tier model. Every file and directory has three sets of permissions assigned to three categories of users:
- Owner (u) — The user who created the file. The owner has the most control and can modify permissions and ownership.
- Group (g) — A collection of users. Files belong to one group, and all members of that group share the same group permissions.
- Others (o) — Everyone else on the system who is neither the owner nor in the file"s group.
Each of these categories can be granted three types of access:
- Read (r = 4) — On files: view contents. On directories: list filenames.
- Write (w = 2) — On files: modify contents. On directories: create, delete, or rename files.
- Execute (x = 1) — On files: run as a program or script. On directories: enter the directory (cd) and access files within.
When you run ls -la, the permission string looks like this: -rwxr-xr--. This breaks down into four parts: the file type indicator (- for regular file, d for directory, l for symlink), followed by three groups of three characters each representing owner, group, and others permissions respectively.
Octal vs Symbolic Notation
Linux provides two notation systems for expressing permissions. Both are widely used, and understanding both is essential for any system administrator:
Octal (Numeric) Notation
Octal notation represents each permission set as a single digit from 0-7, calculated by adding the values of each permission: read (4) + write (2) + execute (1). The most common combinations you will encounter daily:
- 755 (rwxr-xr-x) — Standard for executable files, scripts, and directories. Owner has full control; everyone else can read and execute.
- 644 (rw-r--r--) — Standard for regular files and configuration files. Owner can read and write; everyone else can only read.
- 700 (rwx------) — Private directories and scripts. Only the owner has access. Essential for
~/.sshdirectories. - 600 (rw-------) — Private files like SSH keys, environment files, and database credentials. Only the owner can read and write.
- 775 (rwxrwxr-x) — Shared group directories where team members need write access.
Symbolic Notation
Symbolic notation uses letters and operators to express permission changes more intuitively. It uses u (user/owner), g (group), o (others), and a (all) combined with operators + (add), - (remove), and = (set exactly). For example: chmod u+x script.sh adds execute permission for the owner, while chmod go-w file.txt removes write permission from both group and others.
chmod: Changing Permissions
The chmod (change mode) command is your primary tool for modifying file and directory permissions. It accepts both octal and symbolic notation:
Using Octal Notation
chmod 755 script.sh # Owner: rwx, Group: r-x, Others: r-x
chmod 644 config.yml # Owner: rw-, Group: r--, Others: r--
chmod 600 id_rsa # Owner only: rw- (SSH key requirement)
chmod 700 ~/.ssh # Owner only: rwx (SSH directory requirement)
chmod 775 /var/www/shared # Owner+Group: rwx, Others: r-x
chmod 000 secret.txt # Remove ALL permissions
Using Symbolic Notation
chmod u+x script.sh # Add execute for owner
chmod g+rw shared.txt # Add read+write for group
chmod o-rwx private.key # Remove all permissions for others
chmod a+r readme.txt # Add read for everyone
chmod u=rwx,g=rx,o=r file # Set exact permissions (equals 754)
chmod go-w important.conf # Remove write from group and others
Recursive Permission Changes
One of the most common tasks is setting permissions recursively across directory trees. However, blindly using chmod -R 755 is dangerous because it makes every file executable. The correct approach separates files from directories:
# Set directories to 755 and files to 644 separately:
find /var/www/html -type d -exec chmod 755 {} +
find /var/www/html -type f -exec chmod 644 {} +
# Much safer than: chmod -R 755 /var/www/html
This is a critical best practice that prevents accidental execution of data files, configuration files, and uploaded content — all of which should never have the execute bit set.
chown and chgrp: Changing Ownership
The chown command changes file ownership. Only root (or a user with sudo privileges) can change the owner of a file — this is a security feature preventing unauthorized ownership transfers:
chown alice file.txt # Change owner to alice
chown alice:devs file.txt # Change owner AND group
chown :devs file.txt # Change group only
chown -R www-data:www-data /var/www/ # Recursive ownership change
chown --reference=ref.txt target.txt # Copy ownership from another file
The chgrp command changes just the group. Regular users can use chgrp to change files to groups they belong to:
chgrp devs project/ # Change group to devs
chgrp -R devs project/ # Change group recursively
Understanding the relationship between ownership and permissions is critical. When a user accesses a file, Linux evaluates in strict order: Am I the owner? Am I in the group? Apply "others" permissions. This means owner permissions apply even if the group has more permissive access.
Special Permissions: SUID, SGID, and Sticky Bit
Beyond the standard rwx bits, Linux has three special permission bits that provide powerful (and potentially dangerous) capabilities:
SUID (Set User ID) — Octal: 4xxx
When set on an executable file, SUID causes the program to run with the file owner"s privileges instead of the executing user"s. The classic example is /usr/bin/passwd — owned by root with SUID, it allows regular users to change their own passwords by temporarily running with root privileges.
ls -la /usr/bin/passwd
# -rwsr-xr-x 1 root root 68208 passwd
# ^-- "s" in owner execute position = SUID active
chmod u+s /usr/local/bin/program # Set SUID (symbolic)
chmod 4755 /usr/local/bin/program # Set SUID (octal)
SUID binaries are a major attack surface. Attackers specifically search for SUID programs with vulnerabilities to escalate privileges. Always audit SUID files on your servers:
find / -perm -4000 -type f 2>/dev/null
SGID (Set Group ID) — Octal: 2xxx
On files, SGID works like SUID but for the group. On directories, it is far more commonly used: new files and subdirectories created inside an SGID directory automatically inherit the directory"s group, rather than the creating user"s primary group. This is essential for shared team directories:
mkdir /project/shared
chown :devs /project/shared
chmod 2775 /project/shared
# Now any file created inside inherits group "devs"
Sticky Bit — Octal: 1xxx
When set on a directory, only the file owner, directory owner, or root can delete or rename files within it. The classic example is /tmp where all users can create files, but only owners can delete their own:
ls -ld /tmp
# drwxrwxrwt 22 root root 4096 /tmp
# ^-- "t" in others execute = sticky bit active
chmod +t /shared/uploads # Set sticky bit
chmod 1777 /shared/uploads # Set sticky bit (octal)
Default Permissions and umask
Every time you create a new file or directory, Linux assigns default permissions based on the umask value. The umask defines which permission bits are removed from the maximum default (666 for files, 777 for directories):
- umask 022 → Files: 644, Directories: 755 (standard default on most distributions)
- umask 002 → Files: 664, Directories: 775 (group-friendly, common for shared development)
- umask 077 → Files: 600, Directories: 700 (maximum privacy, recommended for sensitive servers)
- umask 027 → Files: 640, Directories: 750 (group read access, recommended for web servers)
umask # Show current umask value
umask -S # Show in symbolic format
umask 027 # Set restrictive umask for current session
# Make permanent - add to ~/.bashrc or ~/.profile:
echo "umask 027" >> ~/.bashrc
# For system services (systemd):
# Add UMask=0027 in [Service] section of unit file
Access Control Lists (ACLs)
Standard Unix permissions only support one owner and one group per file. When you need to grant specific access to additional users or groups, Access Control Lists (ACLs) provide fine-grained control. ACLs are supported on ext4, XFS, and Btrfs filesystems.
Setting ACLs
setfacl -m u:bob:rw file.txt # Grant bob read+write
setfacl -m g:qa:rx project/ # Grant qa group read+execute
setfacl -m u:bob:--- file.txt # Explicitly deny bob all access
setfacl -x u:bob file.txt # Remove ACL entry for bob
setfacl -b file.txt # Remove ALL ACLs
setfacl -R -m g:devs:rwx project/ # Set ACL recursively
setfacl -d -m g:devs:rwx dir/ # Set default ACL for new files
Reading ACLs
getfacl file.txt
# file: file.txt
# owner: alice
# group: devs
user::rw- # Owner permissions
user:bob:rw- # ACL entry: bob has read+write
group::r-- # Owning group
group:qa:r-x # ACL entry: qa group
mask::rwx # Effective rights mask
other::r-- # Others
# Files with ACLs show "+" in ls output:
# -rw-rw-r--+ 1 alice devs 4096 file.txt
Directory Permissions: The Subtle Differences
Permission behavior on directories is fundamentally different from files, and this is where many administrators make mistakes:
- Read (r) on a directory lets you list filenames with
ls, but without execute (x), you cannot see file details or access files. - Execute (x) on a directory lets you enter it with
cdand access files if you know their names. This is the "traverse" permission. - Write (w) on a directory lets you create and delete files. Without the sticky bit, anyone with write permission can delete anyone"s files.
A critical point: to delete a file, you need write + execute permission on the parent directory, NOT on the file itself. File permissions only control reading and modifying the file"s content. This catches many people off guard during troubleshooting.
Web Server Directory Permissions
# Standard NGINX/Apache web root setup
chown -R www-data:www-data /var/www/html
find /var/www/html -type d -exec chmod 755 {} +
find /var/www/html -type f -exec chmod 644 {} +
# Writable upload directory
chmod 775 /var/www/html/uploads
chown www-data:www-data /var/www/html/uploads
# Secure config files
chmod 640 /var/www/html/.env
chown root:www-data /var/www/html/.env
Finding and Auditing Permission Issues
Regular permission auditing is essential for maintaining server security. The find command is your best tool for discovering permission-related issues:
Security-Critical Searches
# Find all SUID files (potential privilege escalation)
find / -perm -4000 -type f 2>/dev/null
# Find all SGID files
find / -perm -2000 -type f 2>/dev/null
# Find world-writable files (security risk)
find / -xdev -perm -o+w -not -path "/tmp/*" -type f 2>/dev/null
# Find files with no valid owner or group
find / -nouser -o -nogroup 2>/dev/null
# Find 777 permission files (almost always wrong)
find / -perm 777 -type f 2>/dev/null
Useful Inspection Commands
stat file.txt # Full file metadata
stat -c "%a %U:%G %n" file.txt # Compact: 644 alice:devs file.txt
namei -l /full/path/to/file # Permission chain for entire path
ls -laR /etc/ssh/ # Recursive listing
getfacl -R /project/ # Dump all ACLs recursively
The namei -l command is particularly valuable for troubleshooting "Permission denied" errors. It shows the permissions of every directory in the path, making it easy to identify where access is blocked.
Troubleshooting Permission Errors
When you encounter permission errors, follow this systematic checklist:
- Check file permissions:
ls -la file.txt— Do you have the needed r/w/x? - Check the ENTIRE path:
namei -l /full/path/to/file— Every directory in the path needs at least execute (x) permission. - Check ownership:
stat file.txt— Is the owner/group correct? - Check ACLs:
getfacl file.txt— Is an ACL overriding standard permissions? - Check mount options:
mount | grep /path— Is the filesystem mounted withnoexecornosuid? - Check SELinux/AppArmor:
sestatus/aa-status— Is mandatory access control blocking access? - Check immutable flag:
lsattr file.txt— Is the immutable (i) flag set?
SELinux Quick Checks
sestatus # Check SELinux status
ls -Z file.txt # Show SELinux context
ausearch -m AVC -ts recent # Search for SELinux denials
sudo setenforce 0 # Temporarily set permissive (debug only!)
Security Best Practices
Implement these permission best practices across all your Linux servers:
- Principle of Least Privilege: Grant only the minimum permissions needed. Start restrictive and add access as required.
- Never use 777: There is almost never a legitimate reason for world-writable, world-executable files. If you find yourself reaching for 777, rethink your ownership and group strategy.
- Separate file and directory permissions: Use
find -type fandfind -type dinstead of recursive chmod. - Protect sensitive files: SSH keys (600), .env files (640), database credentials (600).
- Use SGID for shared directories: Ensures consistent group ownership for team collaboration.
- Set sticky bit on shared writable directories: Prevents users from deleting each other"s files.
- Audit SUID/SGID files regularly: Run weekly scans and compare against a known-good baseline.
- Use restrictive umask: Set
umask 027or077on production servers. - Use ACLs when owner/group/others is insufficient: Cleaner than changing group memberships for temporary access.
Download the Complete Cheat Sheet
We have prepared a comprehensive 12-page PDF cheat sheet covering everything in this guide in a quick-reference format. It includes permission tables, command syntax, octal lookup charts, special permission references, ACL commands, troubleshooting checklists, and security audit one-liners — all formatted for easy printing and desk reference.
Download the Linux File Permissions Cheat Sheet 2026 (Free PDF)
Recommended Books for Deeper Learning
To master Linux permissions and security at a professional level, we recommend these resources from our collection:
- Linux Permissions — Our dedicated deep-dive into the permission system, covering every concept in detail with hands-on labs.
- Linux File System & Permissions Deep Dive — Advanced guide covering ACLs, extended attributes, filesystem-level security, and enterprise permission strategies.
- Linux User & Group Management — Essential companion covering the user/group side of the permission equation.
- Linux System Hardening — Comprehensive security hardening guide where permissions are a key chapter.
- Linux Security Essentials — Broader security context including permissions, firewalls, and intrusion detection.
- SELinux & AppArmor Guide — For understanding mandatory access control systems that work alongside traditional permissions.
Conclusion
Linux file permissions are deceptively simple in concept but remarkably powerful in practice. The three-tier rwx model, combined with special bits, ACLs, and mandatory access control systems, provides enterprise-grade security for any Linux environment. The key is understanding not just the commands, but the underlying model — how Linux evaluates permissions in order, how directory permissions differ from file permissions, and how special bits like SUID can be both essential tools and security risks.
Start with the fundamentals, practice with real scenarios, audit your systems regularly, and always follow the principle of least privilege. With the knowledge from this guide and the accompanying cheat sheet, you are well equipped to manage permissions confidently on any Linux system.