Unix File Permissions Explained for Humans
By The IT Hustle Team
This article was generated with AI assistance and reviewed by our team for accuracy and quality. All technical information and examples have been verified.
You set up a web server. Everything looks good. You navigate to your site and get a 403 Forbidden error. Or you write a script, try to run it, and get "Permission denied." Or you deploy an application and it can't read its own configuration file. Every time, the answer is the same: file permissions.
Unix file permissions are one of those concepts that seem simple on the surface but trip up even experienced developers. The good news is that once you genuinely understand the system — not just memorize chmod 755 — you'll never be confused by a permission error again.
Let's break this down from the ground up, assuming you're starting from zero.
The Three Categories: User, Group, Others
Every file and directory on a Unix system has an owner and a group. When the system checks whether you can access a file, it asks three questions in order:
- User (u): Are you the file's owner? If yes, user permissions apply.
- Group (g): Are you a member of the file's group? If yes (and you're not the owner), group permissions apply.
- Others (o): If you're neither the owner nor in the group, "others" permissions apply.
This is the fundamental model. Every permission decision on a Unix system flows from this three-tier classification. The system doesn't combine them — it uses the first match. If you're the owner, only the user permissions matter, even if the group or others permissions are more permissive.
You can see the owner and group of any file with ls -l:
-rw-r--r-- 1 sarah webteam 4096 Mar 15 10:30 index.html
↑ ↑
owner group
The Three Permissions: Read, Write, Execute
Each of the three categories (user, group, others) can have three permissions:
- Read (r): For files, you can view the contents. For directories, you can list the filenames inside.
- Write (w): For files, you can modify the contents. For directories, you can create, delete, or rename files inside.
- Execute (x): For files, you can run it as a program. For directories, you can
cdinto it and access files inside.
Why it matters:
The execute permission on directories is the one that surprises people most. A directory with read but no execute permission lets you see the filenames inside (via ls) but you can't access any of the files or their metadata. Conversely, execute without read lets you access files if you know their names, but you can't list the directory contents. This distinction is actually used for security in some configurations.
Reading Permission Strings
When you run ls -l, you see a 10-character permission string. Here's how to read it:
Position 1: - = regular file (d = directory, l = symlink)
Positions 2-4: rwx = owner can read, write, and execute
Positions 5-7: r-x = group can read and execute (no write)
Positions 8-10: r-- = others can only read
Each dash represents an absent permission. So r-x means read and execute but not write. --- means no permissions at all.
Octal Notation: The Number System
Instead of typing rwxr-xr--, Unix uses a three-digit octal number to represent permissions. Each digit represents one category (user, group, others), and each permission has a numeric value:
- Read = 4
- Write = 2
- Execute = 1
You add the values together to get the digit for each category. So:
r-x = 4 + 0 + 1 = 5
r-- = 4 + 0 + 0 = 4
rw- = 4 + 2 + 0 = 6
--- = 0 + 0 + 0 = 0
So rwxr-xr-- = 754
And rwxr-xr-x = 755
And rw-r--r-- = 644
Once you internalize this mapping, you'll read permission numbers instantly. The key insight is that each digit is independent — the first digit is always the owner, the second is always the group, and the third is always others.
If math isn't your thing, use our Chmod Calculator to convert between symbolic and octal notation with a visual interface. Toggle permissions on and off and see the corresponding chmod command in real time.
Common Permission Patterns
You'll encounter these permission patterns constantly. Memorize what they mean and when to use them:
644 — Standard Files
Owner: read + write
Group: read only
Others: read only
This is the default for most regular files — HTML, CSS, images, configuration files. The owner can edit them, everyone else can read them. This is what your web server files should typically be.
755 — Executable Files and Directories
Owner: read + write + execute
Group: read + execute
Others: read + execute
This is the standard for directories and executable scripts. The owner has full control, everyone else can read and execute (for files) or enter and list (for directories). Most web server directories should be 755.
700 — Private Files and Directories
Owner: read + write + execute
Group: none
Others: none
Only the owner can access these. Use this for sensitive directories like ~/.ssh, private key storage, and personal scripts. If anyone else needs access, they shouldn't have it — use a different mechanism.
600 — Private Data Files
Owner: read + write
Group: none
Others: none
Like 700 but without execute. This is what SSH expects for private key files (~/.ssh/id_rsa). In fact, SSH will refuse to use a private key with more permissive settings — it's one of the few programs that actively checks permissions.
Other Common Patterns
777 (rwxrwxrwx) — Everyone can do everything (NEVER use this in production)
750 (rwxr-x---) — Owner full access, group can read/execute, others blocked
640 (rw-r-----) — Owner read/write, group read only, others blocked
444 (r--r--r--) — Read-only for everyone, including the owner
The chmod Command
chmod (change mode) is the command that sets file permissions. It accepts either octal notation or symbolic notation:
chmod 755 script.sh
chmod 644 index.html
chmod 600 ~/.ssh/id_rsa
# Symbolic notation (add/remove specific permissions)
chmod u+x script.sh # add execute for user (owner)
chmod g-w config.yml # remove write for group
chmod o-rwx secret.key # remove all permissions for others
chmod a+r readme.txt # add read for all (user + group + others)
chmod u=rwx,g=rx,o=r file # set exact permissions symbolically
# Recursive (apply to directory and everything inside)
chmod -R 755 /var/www/html/
Symbolic notation is useful when you want to change one specific permission without knowing or affecting the others. Octal notation is useful when you want to set all permissions at once to a known state.
Why it matters:
Be extremely careful with chmod -R (recursive). Applying 755 recursively to a directory makes all files executable, which is usually wrong — regular files should typically be 644. A better approach is to set directories and files separately:
find /var/www/html -type d -exec chmod 755 {} \;
find /var/www/html -type f -exec chmod 644 {} \;
chown and chgrp: Changing Ownership
Sometimes the issue isn't the permission bits — it's who owns the file. chown changes the owner, and chgrp changes the group:
chown sarah file.txt
# Change owner and group
chown sarah:webteam file.txt
# Change group only
chgrp webteam file.txt
# Recursive ownership change
chown -R www-data:www-data /var/www/html/
A classic mistake: deploying web files as root but running the web server as www-data. The files have correct permissions (644), but the web server user isn't the owner and isn't in the right group, so it falls into the "others" category. Fix it by changing ownership to the web server user, or add the web server user to the file's group.
Special Permissions: setuid, setgid, and Sticky Bit
Beyond the basic rwx permissions, Unix has three special permission bits that you'll encounter in specific scenarios:
setuid (Set User ID) — 4xxx
When set on an executable file, it runs with the permissions of the file's owner instead of the user who executed it. The classic example is /usr/bin/passwd — it needs to modify /etc/shadow (which only root can write), so it has the setuid bit set and is owned by root. Any user can run passwd, and it executes with root privileges.
-rwsr-xr-x 1 root root 68208 Mar 15 10:30 /usr/bin/passwd
↑ the 's' instead of 'x' indicates setuid
chmod 4755 myprogram # set the setuid bit
Security warning: setuid on a script or program you don't trust is an enormous security risk. It effectively gives anyone who runs that program the owner's privileges. Only system programs should have setuid, and you should audit any setuid binaries on your system regularly.
setgid (Set Group ID) — 2xxx
On files, setgid works like setuid but for the group — the program runs with the file's group permissions. More commonly, setgid is used on directories: when set on a directory, new files created inside automatically inherit the directory's group instead of the creating user's primary group.
mkdir /opt/project
chgrp developers /opt/project
chmod 2775 /opt/project
# Now any file created inside will belong to the 'developers' group
# regardless of who creates it
This is incredibly useful for shared directories where multiple users need to collaborate. Without setgid, files would be created with each user's primary group, and other team members might not have access.
Sticky Bit — 1xxx
The sticky bit on a directory prevents users from deleting or renaming files they don't own, even if they have write permission on the directory. The classic example is /tmp:
drwxrwxrwt 22 root root 4096 Mar 15 10:30 /tmp
↑ the 't' instead of 'x' indicates sticky bit
chmod 1777 /tmp # set sticky bit
Without the sticky bit, anyone with write permission on /tmp could delete anyone else's temporary files. The sticky bit ensures you can only delete your own files, even in a world-writable directory.
Real-World Scenarios
Web Server Files
The most common permission-related question: "What permissions should my web files have?"
chown -R www-data:www-data /var/www/html
# Directories: 755 (owner rwx, group and others rx)
find /var/www/html -type d -exec chmod 755 {} \;
# Files: 644 (owner rw, group and others r)
find /var/www/html -type f -exec chmod 644 {} \;
# Upload directories (web server needs to write): 775
chmod 775 /var/www/html/uploads
SSH Keys
SSH is famously strict about permissions. If your key files are too permissive, SSH refuses to use them:
chmod 600 ~/.ssh/id_rsa # private key: owner read/write only
chmod 644 ~/.ssh/id_rsa.pub # public key: owner rw, others read
chmod 600 ~/.ssh/authorized_keys # authorized keys: owner only
chmod 644 ~/.ssh/config # SSH config: owner rw, others read
If you get the dreaded "Permissions 0644 for 'id_rsa' are too open" error, now you know why. SSH protects you from accidentally exposing your private key.
Shell Scripts
A script needs execute permission to be run directly. Without it, you get "Permission denied":
chmod +x deploy.sh
# Or with explicit permissions
chmod 755 deploy.sh # everyone can run it
chmod 700 deploy.sh # only owner can run it
Note: you can always bypass the execute permission by calling the interpreter directly: bash deploy.sh works even without execute permission, because bash itself has execute permission and it's just reading the script as a text file. The execute bit only matters when you run ./deploy.sh directly.
Common Permission Mistakes
These are the mistakes I see repeatedly, especially from developers who are more comfortable with application code than system administration:
- chmod 777 everything: This is the "I don't understand permissions so I'll just open everything up" approach. It's a massive security hole. Anyone on the system can read, modify, and execute your files. Never do this in production.
- Running everything as root: If you sudo everything, permissions never cause problems — but you also have no protection against mistakes or malicious code. Root can delete your entire system with a typo.
- Forgetting directory execute: Setting a directory to 644 (rw-r--r--) means nobody can
cdinto it or access files inside, even though they can see the filenames withls. Directories almost always need execute permission. - Recursive chmod on /: Running
chmod -R 755 /will make your system unusable. It changes permissions on critical system files, including/etc/shadow(which needs to be 640 or 600) and setuid binaries (which lose their setuid bit). - Ignoring umask: The umask determines the default permissions for newly created files. If your umask is 022, new files get 644 and new directories get 755. If it's 077, new files get 600 and new directories get 700. Know your umask.
- Wrong ownership after sudo: Creating files with sudo makes them owned by root. If your application runs as a different user, it can't read or write those files even with correct permission bits.
Understanding umask
The umask is a value that determines what permissions are removed from newly created files and directories. It's a mask, not a setting — it subtracts permissions from the maximum.
umask
# Common values:
# umask 022 → files: 644, directories: 755 (default on most systems)
# umask 027 → files: 640, directories: 750 (more restrictive)
# umask 077 → files: 600, directories: 700 (private)
# How it works:
# Maximum file permissions: 666 (no execute by default)
# Maximum directory permissions: 777
# Subtract umask: -022
# Result for files: 644
# Result for directories: 755
Note that new files never get execute permission by default, regardless of umask. This is a security measure — you have to explicitly make files executable with chmod +x.
Security Implications
File permissions are a fundamental security boundary on Unix systems. Getting them wrong can expose sensitive data, allow unauthorized modifications, or enable privilege escalation:
- Configuration files with database passwords should be 600 or 640, never world-readable
- Log files should be 640 — readable by the application and its group, not by everyone
- Upload directories should never have execute permission on uploaded files
- Cron scripts should be owned by root and not writable by other users (otherwise anyone can escalate privileges)
- Audit setuid and setgid binaries regularly:
find / -perm -4000 -type f - World-writable directories without the sticky bit are a security risk
The principle of least privilege applies directly to file permissions: every file should have the minimum permissions needed for the system to function. Start restrictive and open up as needed, not the other way around.
Debugging Permission Issues
When you hit a permission error, here's a systematic debugging approach:
whoami
id # shows your user ID, group ID, and all groups
# 2. Check the file's permissions and ownership
ls -la /path/to/file
# 3. Check every directory in the path (all need execute permission)
namei -l /path/to/file
# 4. Check if SELinux or AppArmor is blocking access
getenforce # SELinux status
ls -Z /path/to/file # SELinux context
# 5. Check ACLs (access control lists) if basic permissions look correct
getfacl /path/to/file
Step 3 is the one people forget most often. Even if the target file has correct permissions, you need execute permission on every directory in the path to reach it. A common scenario: /home/sarah/public_html/index.html is 644, but /home/sarah is 700, so the web server (running as www-data) can't traverse into the home directory.
Beyond Basic Permissions: ACLs
The traditional user/group/others model has a limitation: there's only one group. What if you need multiple groups with different levels of access? That's where Access Control Lists (ACLs) come in. ACLs let you set permissions for specific users and groups beyond the basic three categories:
setfacl -m u:bob:r /opt/reports/quarterly.pdf
# Grant a specific group read/write access
setfacl -m g:editors:rw /opt/content/draft.txt
# View ACLs
getfacl /opt/reports/quarterly.pdf
ACLs are more flexible but also more complex. For most scenarios, getting the basic user/group/others permissions right is sufficient. Use ACLs when you genuinely need more granularity.
File permissions are not glamorous. They won't make it into your portfolio or your LinkedIn headline. But they are the difference between a secure system and an exposed one, between an application that works and one that fails with cryptic errors. Master them, and a whole category of frustrating bugs becomes trivial to diagnose and fix.
Need to calculate permissions quickly? The Chmod Calculator lets you toggle permission bits visually and see the corresponding octal value and chmod command. No more mental arithmetic.
Every 403 Forbidden error, every "Permission denied," every SSH key rejection — they all come back to these same fundamentals. Learn them once, solve permission problems forever. Calculate your permissions with the Chmod Calculator.
We build free developer tools and write about AI, automation, and developer productivity. 30 tools, 33 articles, and an AI Prompt Engine — all built to help workers navigate the AI era. Published by Salty Rantz LLC.
The IT Hustle Weekly
What changed in AI this week and what it means for your job. Free tools, honest reviews, zero spam.
Generate Your Own Anti-Hallucination Prompts
Our AI Prompt Engine uses patent-pending technology to generate prompts with built-in verification and contradiction testing.
Try 3 Free Generations →