File permissions are one of the first things that trip up developers on Linux and macOS. You get a "Permission denied" error, frantically Google "chmod 777", fix it, and move on — without really understanding what happened.
This guide gives you a practical understanding of Unix permissions that will save you from both "Permission denied" errors and accidental security holes. Whether you are deploying web applications, managing SSH keys, or scripting server automation, having chmod permissions explained clearly will make you a more effective developer.
The Owner / Group / Other Permission Model
Every file and directory on a Unix system has three sets of permissions for three classes of users:
- Owner (u) — the user who owns the file. By default, the user who creates a file becomes its owner.
- Group (g) — users in the file's group. Every file is assigned to one group, and any user who is a member of that group gets these permissions.
- Others (o) — everyone else on the system who is neither the owner nor in the file's group.
Each class can have three permissions:
- Read (r = 4) — view file contents, list directory contents
- Write (w = 2) — modify file, create/delete files in directory
- Execute (x = 1) — run file as program, access directory (cd into it)
This three-by-three model creates a total of nine permission bits. Understanding how these bits interact is the key to managing file security on any Unix-like operating system.
How Ownership Is Determined
When you create a file, the operating system automatically sets you as the owner. The file's group is typically set to your primary group (which you can check with the id command). You can change ownership with chown and group with chgrp:
chown alice file.txt # Change owner to alice
chgrp developers file.txt # Change group to developers
chown alice:developers file.txt # Change both at once
Only the root user (or a user with sudo) can change file ownership. Regular users can only change the group to another group they belong to.
Reading Permission Output
When you run ls -la, you see permissions like -rwxr-xr-x. Here's how to read it:
- rwx r-x r-x
│ │ │ │
│ │ │ └── Others: read + execute (no write)
│ │ └────── Group: read + execute (no write)
│ └────────── Owner: read + write + execute
└──────────── File type (- = file, d = directory, l = symlink) Each position is either the permission letter or a dash. Dashes mean "not granted." The file type character at the beginning is not a permission — it tells you what kind of filesystem entry you are looking at:
-— regular filed— directoryl— symbolic linkc— character deviceb— block devices— socketp— named pipe (FIFO)
Octal vs Symbolic Notation: A Complete Comparison
There are two ways to express Unix file permissions: octal (numeric) and symbolic. Both are used with the chmod command, and each has advantages depending on the situation.
Octal (Numeric) Notation
The octal system represents each permission set as a single digit from 0 to 7. Each permission has a numeric value:
r= 4,w= 2,x= 1- Add them up:
rwx= 4+2+1 = 7 r-x= 4+0+1 = 5r--= 4+0+0 = 4-w-= 0+2+0 = 2--x= 0+0+1 = 1---= 0+0+0 = 0
So -rwxr-xr-x = 755. Three digits: owner, group, others. Here is the full reference table for a single digit:
| Octal | Binary | Symbolic | Meaning |
|---|---|---|---|
| 0 | 000 | --- | No permissions |
| 1 | 001 | --x | Execute only |
| 2 | 010 | -w- | Write only |
| 3 | 011 | -wx | Write + execute |
| 4 | 100 | r-- | Read only |
| 5 | 101 | r-x | Read + execute |
| 6 | 110 | rw- | Read + write |
| 7 | 111 | rwx | Read + write + execute |
Symbolic Notation
Symbolic notation uses letters and operators to modify permissions. It is more flexible when you want to change specific bits without affecting others:
chmod u+x script.sh # Add execute for owner
chmod go-w config.json # Remove write from group and others
chmod a+r README.md # Add read for all users
chmod u=rwx,g=rx,o=r file # Set exact permissions The operators are:
+— add the specified permission-— remove the specified permission=— set permissions exactly (removes anything not listed)
The user classes are:
u— owner (user)g— groupo— othersa— all (equivalent to ugo)
When to Use Which?
Use octal notation when you want to set all permissions at once and know exactly what the result should be. It is concise and unambiguous — chmod 644 file always produces the same result regardless of the file's current permissions.
Use symbolic notation when you want to modify one specific permission without touching the rest. For example, chmod +x script.sh adds execute without changing any read or write bits.
Use our Chmod Calculator to convert between octal, symbolic, and see the chmod command ready to copy. If you are working with number conversions in other contexts, our Number Base Converter can help with octal-to-binary and other base conversions.
Common Permission Patterns
Here is a comprehensive reference table of the most common chmod permission patterns, what they mean, and when to use them:
| Octal | Symbolic | Use Case | Example |
|---|---|---|---|
| 777 | rwxrwxrwx | Full access for everyone (avoid in production) | Temporary debug only |
| 755 | rwxr-xr-x | Executables, directories, public scripts | Web root, shell scripts |
| 750 | rwxr-x--- | Group-accessible executables and directories | Shared project directories |
| 700 | rwx------ | Private directories | ~/.ssh, ~/private |
| 666 | rw-rw-rw- | Read/write for everyone (rare, usually a mistake) | Shared temp files |
| 664 | rw-rw-r-- | Owner+group can edit, others read-only | Shared project files |
| 644 | rw-r--r-- | Regular files (default) | HTML, CSS, config files |
| 640 | rw-r----- | Owner edits, group reads, no public access | Application config files |
| 600 | rw------- | Private files (owner only) | .env, credentials, database config |
| 400 | r-------- | Read-only private files | SSH private keys, TLS certificates |
| 444 | r--r--r-- | Read-only for everyone | Published reference files |
755 — Standard for Executables and Directories
chmod 755 script.sh
chmod 755 /var/www/html Owner can read, write, and execute. Everyone else can read and execute but not modify. This is the default for directories and executable scripts.
644 — Standard for Regular Files
chmod 644 index.html
chmod 644 config.json Owner can read and write. Everyone else can only read. This is the default for most files.
600 — Private Files
chmod 600 .env
chmod 600 credentials.json Only the owner can read and write. No access for anyone else. Use this for sensitive files like environment variables, database credentials, and private keys. If you are generating credentials, our Password Generator can create strong, random passwords.
400 — Read-Only Private Files
chmod 400 ~/.ssh/id_rsa Owner can only read. SSH actually requires this — it refuses to use private keys with more permissive settings. If you get "Permissions 0644 for '~/.ssh/id_rsa' are too open", this is the fix.
700 — Private Directories
chmod 700 ~/.ssh
chmod 700 ~/private Only the owner can access the directory at all. Others can't even list its contents.
750 — Group-Shared Directories
chmod 750 /var/www/project
chgrp developers /var/www/project Owner has full access, group members can read and enter the directory, and others have no access at all. This is ideal for team projects on shared servers.
The chmod Command in Depth
Octal Mode
chmod 755 file.sh # Set exact permissions
chmod -R 644 ./docs # Recursive (all files in docs/) Symbolic Mode
Symbolic mode lets you add or remove specific permissions without changing others:
chmod +x script.sh # Add execute for everyone
chmod u+w file.txt # Add write for owner
chmod go-w file.txt # Remove write for group and others
chmod a+r file.txt # Add read for all (a = all)
chmod u=rwx,go=rx dir # Set exact: owner=rwx, group+others=rx Useful chmod Flags
-R— apply recursively to all files and subdirectories-v— verbose mode, shows each file being changed-c— like verbose but only shows files that actually changed--reference=FILE— copy permissions from another file
chmod --reference=known-good.conf new.conf # Match permissions from another file
chmod -Rv 755 /var/www/html/ # Recursive with verbose output Directory vs File Permissions
The same permission bits mean different things for files and directories:
- Read on directory = list contents (
ls) - Write on directory = create/delete files inside it
- Execute on directory = access directory (
cdinto it, access files by path)
A common gotcha: a directory needs execute permission for users to access files inside it, even if those files have read permission. Without x on the directory, users can't reach the files. This is why directories almost always have execute permission (755 or 700) while regular files do not (644 or 600).
Another subtlety: having write permission on a directory means you can delete any file in that directory, even files you do not own and cannot read. This is why the sticky bit (covered below) exists.
Special Permissions: Setuid, Setgid, and Sticky Bit
Beyond the basic nine rwx bits, Unix has three special permission bits that control advanced behavior. These are represented by an optional fourth digit prepended to the octal notation.
Setuid (4000) — Run as File Owner
When the setuid bit is set on an executable file, the program runs with the permissions of the file's owner, not the user executing it. This is how the passwd command works — it is owned by root and has setuid set, which allows regular users to modify the /etc/shadow file that only root can write to.
chmod 4755 /usr/bin/passwd
# ls -la shows: -rwsr-xr-x
Notice the s in the owner's execute position. A lowercase s means both setuid and execute are set. An uppercase S means setuid is set but execute is not (which is usually a misconfiguration).
Security warning: Setuid programs are a common attack vector. Never set setuid on scripts, and audit any setuid binaries on your system regularly.
Setgid (2000) — Run as File Group or Inherit Group
On executable files, setgid works like setuid but for the group — the program runs with the file's group permissions. On directories, setgid has a different and very useful behavior: new files and subdirectories created inside inherit the directory's group instead of the creating user's primary group.
# Set setgid on a shared directory
chmod 2775 /var/www/shared
chgrp webdevs /var/www/shared
# Now any file created inside /var/www/shared
# automatically belongs to the "webdevs" group This is invaluable for team collaboration. Without setgid, files created by different users would belong to each user's primary group, making shared access unpredictable.
# ls -la shows: drwxrwsr-x
# Note the 's' in the group execute position Sticky Bit (1000) — Restrict Deletion
The sticky bit on a directory prevents users from deleting files they do not own. Without it, anyone with write permission on the directory can delete any file inside it. The classic example is /tmp:
chmod 1777 /tmp
# ls -la shows: drwxrwxrwt
# Note the 't' in the others execute position
The t at the end indicates the sticky bit. With this set, anyone can create files in /tmp, but only the file's owner (or root) can delete them. This prevents users from deleting each other's temporary files.
Combining Special Permissions
Special permissions are added as a leading digit in octal notation:
chmod 4755 file # setuid + rwxr-xr-x
chmod 2755 dir # setgid + rwxr-xr-x
chmod 1777 dir # sticky + rwxrwxrwx
chmod 6755 file # setuid + setgid + rwxr-xr-x Use our Chmod Calculator to experiment with these special permission bits visually.
Step-by-Step Tutorial: Using the DevToolkit Chmod Calculator
If calculating octal values in your head feels error-prone, the DevToolkit Chmod Calculator makes it visual and instant. Here is how to use it:
- Open the tool — Navigate to DevToolkit Chmod Calculator in your browser.
- Toggle permission checkboxes — Click the read, write, and execute checkboxes for Owner, Group, and Others. Each click immediately updates the octal value and the symbolic representation.
- Or type an octal number — If you already have a permission number like
644, type it in the octal input field. The checkboxes and symbolic notation update automatically. - Review the generated command — The tool generates the full
chmodcommand (e.g.,chmod 755 filename) ready to copy. - Copy to clipboard — Click the copy button and paste the command directly into your terminal.
This is especially useful when you are configuring server deployments, writing CI/CD scripts, or setting up cron jobs that need specific file permissions. If you are building deployment scripts, you might also find our Regex Tester helpful for parsing log files and our JSON Formatter useful for reading configuration files.
Security Best Practices: The Principle of Least Privilege
The golden rule of file permissions is the principle of least privilege: grant only the minimum permissions needed for a file or directory to function correctly. Here are concrete guidelines:
For Web Applications
- Web root directory:
755(owner: deploy user, group: www-data) - PHP/Python/application files:
644 - Upload directories:
775(so the web server group can write) - Configuration files with secrets:
640or600 - Log files:
640 - Never use
777on production servers
For SSH
~/.ssh/directory:700~/.ssh/authorized_keys:600~/.ssh/id_rsa(private key):400~/.ssh/id_rsa.pub(public key):644~/.ssh/config:600
For Application Secrets
.envfiles:600- API key files:
600 - TLS/SSL certificates:
644(public cert) or600(private key) - Database credential files:
600
To generate secure credentials for these files, use our Password Generator. For encoding sensitive data in configuration, our Base64 Encoder and Hash Generator can be useful. If you are working with JWT tokens, the JWT Decoder helps verify token contents without exposing secrets.
Common Mistakes and Troubleshooting
Mistake 1: chmod 777 Everything
chmod 777 gives everyone full access. This is a security risk and usually means you don't understand what permission is actually needed. Instead:
- If a web server needs to read a file:
644and make sure the web server user owns it (or is in the group) - If a script needs to be executable:
755 - If only your user needs access:
600or700
Mistake 2: Recursive chmod on Mixed Content
Running chmod -R 755 . gives everything execute permission — including text files, images, and configs that should never be executable. Instead, set files and directories separately:
# Directories: 755 (need execute for cd)
find . -type d -exec chmod 755 {} \;
# Files: 644 (don't need execute)
find . -type f -exec chmod 644 {} \; Mistake 3: Forgetting Group Permissions
On shared servers, group permissions matter. If multiple users need to edit files in a shared directory, set the group appropriately:
chgrp -R developers /var/www/project
chmod -R 775 /var/www/project Mistake 4: Ignoring umask
The umask controls the default permissions for newly created files. A umask of 022 means new files get 644 and new directories get 755. A umask of 077 means new files get 600 and directories get 700. If your files always seem to have the wrong permissions, check your umask:
umask # Show current umask
umask 022 # Set standard umask (files: 644, dirs: 755)
umask 077 # Set restrictive umask (files: 600, dirs: 700)
The umask is subtracted from the maximum permissions (666 for files, 777 for directories). So with a umask of 027, new files get 640 and new directories get 750.
Mistake 5: Not Using Groups Effectively
Instead of loosening permissions with chmod 777, add users to appropriate groups and use group permissions:
# Create a group for the project
sudo groupadd webdevs
# Add users to the group
sudo usermod -aG webdevs alice
sudo usermod -aG webdevs bob
# Set the directory group and permissions
chgrp -R webdevs /var/www/project
chmod -R 2775 /var/www/project # setgid ensures new files inherit group Troubleshooting "Permission Denied" Errors
When you encounter "Permission denied", follow this diagnostic checklist:
- Check the file permissions:
ls -la /path/to/file - Check who you are:
whoamiandid - Check directory permissions: You need execute on every directory in the path. Run
namei -l /path/to/fileto see permissions on each component. - Check for ACLs:
getfacl /path/to/file— Access Control Lists can override basic permissions. - Check SELinux/AppArmor: On systems with mandatory access control, regular permissions might not be enough. Check
ls -Zfor SELinux contexts.
umask: Controlling Default Permissions
While chmod changes existing permissions, umask controls what permissions new files and directories receive. Understanding umask prevents you from having to chmod every new file.
The umask value is a mask that is subtracted from the maximum permissions. Files have a maximum of 666 (no execute by default) and directories have a maximum of 777:
| umask | New File | New Directory | Use Case |
|---|---|---|---|
| 022 | 644 | 755 | Standard (most systems) |
| 027 | 640 | 750 | Group-friendly, no public |
| 077 | 600 | 700 | Private (security-sensitive) |
| 002 | 664 | 775 | Collaborative (group writable) |
Set your umask in ~/.bashrc or ~/.profile for persistent configuration. For servers handling sensitive data, a umask of 077 is a good baseline.
Frequently Asked Questions
What does chmod 755 mean?
chmod 755 sets the file to be readable, writable, and executable by the owner, and readable and executable (but not writable) by the group and others. In symbolic notation, this is rwxr-xr-x. It is the standard permission for executable scripts and directories.
What is the difference between chmod 644 and 755?
The difference is the execute bit. 644 (rw-r--r--) does not grant execute permission to anyone — use this for regular files like HTML, CSS, images, and config files. 755 (rwxr-xr-x) grants execute permission — use this for scripts, binaries, and directories (which need execute for users to enter them).
Why is chmod 777 dangerous?
chmod 777 grants read, write, and execute permissions to every user on the system. This means any user or process can modify or delete the file. On a web server, this could allow an attacker to inject malicious code. Always use the minimum permissions required.
How do I make a file executable in Linux?
Use chmod +x filename to add execute permission for all users, or chmod u+x filename to add it only for the owner. For scripts, you also need a shebang line (e.g., #!/bin/bash) at the top of the file.
What permissions should .env files have?
Environment files containing secrets (API keys, database passwords, etc.) should have 600 permissions — only the owner can read and write. Never commit .env files to version control either; add them to your .gitignore.
How do I check current file permissions?
Use ls -la filename to see permissions in symbolic format, or stat filename for more detailed information including the octal representation. You can also use our Chmod Calculator to decode octal values into human-readable format.
What is the difference between chmod and chown?
chmod changes what actions (read, write, execute) are allowed. chown changes who owns the file. Often you need both — for example, setting the correct owner and the correct permissions for a web server to access files properly.
Can I undo a chmod command?
There is no built-in undo for chmod. If you accidentally change permissions and do not remember the original values, check your backup or use chmod --reference=similar_file broken_file to copy permissions from a known-good file. This is why it is always a good idea to check permissions with ls -la before changing them.
Related Tools and Resources
Working with Unix systems involves more than just file permissions. Here are other DevToolkit tools that complement your workflow:
- Chmod Calculator — Visually set and convert file permissions
- Cron Expression Generator — Build cron schedules for automated scripts (see our cron cheat sheet)
- Regex Tester — Test patterns for log parsing and file matching (see our regex cheat sheet)
- Hash Generator — Generate MD5, SHA-256, and other hashes for file integrity checks
- Password Generator — Create strong passwords for system accounts
- Base64 Encoder/Decoder — Encode credentials and certificates (learn more in our Base64 guide)
- JSON Formatter — Format and validate server configuration files
Conclusion
File permissions are simple once you understand the model: three user classes, three permission types, three digits. With the addition of special permissions (setuid, setgid, sticky bit), umask defaults, and group management, you have a complete toolkit for securing files on any Unix-like system.
Remember the essentials: use 644 for regular files, 755 for directories and scripts, 600 for sensitive files, and never use 777 unless you genuinely want every user on the system to have full access. When in doubt, follow the principle of least privilege — start restrictive and loosen only as needed.
Need to calculate permissions quickly? Our Chmod Calculator lets you toggle permissions visually and copies the chmod command to your clipboard — no mental math required.