Linux File Permissions and Chmod: A Practical Guide for Developers
Understanding Linux File Permissions
File permissions are one of the most fundamental security mechanisms in Linux and Unix-like operating systems. Every file and directory on a Linux system has an associated set of permissions that determine who can read, write, or execute it. Understanding these permissions is essential for every developer who works with servers, deploys applications, or manages any Linux-based infrastructure.
Linux file permissions are built around two core concepts: three types of permissions and three categories of users. The three permission types are:
- Read (r): Allows viewing the contents of a file, or listing the contents of a directory.
- Write (w): Allows modifying or deleting a file, or adding/removing files within a directory.
- Execute (x): Allows running a file as a program or script, or entering (cd into) a directory.
These three permissions are assigned independently to three categories of users:
- Owner (u): The user who owns the file. By default, the user who creates a file becomes its owner.
- Group (g): A set of users who share the same group membership. Each file belongs to one group.
- Others (o):Everyone else on the system who is not the owner and not in the file's group.
You can view file permissions using the ls -la command. The output looks like this:
$ ls -la
-rwxr-xr-x 1 alice developers 4096 Mar 15 10:30 deploy.sh
-rw-r--r-- 1 alice developers 2048 Mar 15 09:15 config.json
drwxr-x--- 2 alice developers 4096 Mar 14 16:00 secrets/
-rw------- 1 alice developers 1024 Mar 14 15:00 .envThe first column shows the permission string. The very first character indicates the file type: - for a regular file, d for a directory, and l for a symbolic link. The remaining nine characters are grouped into three sets of three, representing the permissions for owner, group, and others respectively. For example, -rwxr-xr-x means: regular file, owner can read/write/execute, group can read/execute, others can read/execute.
The Permission Bits Explained
Under the hood, Linux represents each permission as a single bit. Each permission type has a corresponding numeric value:
- Read (r) = 4 — binary
100 - Write (w) = 2 — binary
010 - Execute (x) = 1 — binary
001
To determine the numeric value for a set of permissions, you simply add the values together. For each user category (owner, group, others), you calculate a single digit from 0 to 7. The three digits combined form the complete permission code:
rwx = 4 + 2 + 1 = 7 (read + write + execute)
rw- = 4 + 2 + 0 = 6 (read + write)
r-x = 4 + 0 + 1 = 5 (read + execute)
r-- = 4 + 0 + 0 = 4 (read only)
--- = 0 + 0 + 0 = 0 (no permissions)
Examples:
755 = rwx(7) r-x(5) r-x(5) → Owner: full, Group: read+exec, Others: read+exec
644 = rw-(6) r--(4) r--(4) → Owner: read+write, Group: read, Others: read
777 = rwx(7) rwx(7) rwx(7) → Everyone: full access (dangerous!)
600 = rw-(6) ---(0) ---(0) → Owner: read+write, no one elseTip: An easy way to remember the values is that they follow powers of 2: read is 22 (4), write is 21 (2), and execute is 20 (1). Use the Chmod Calculator to quickly convert between numeric and symbolic notation without memorizing the math.
Numeric vs Symbolic Notation
Linux supports two different notations for specifying file permissions: numeric (octal) and symbolic. Both accomplish the same thing, but each has its strengths depending on the situation.
Numeric (Octal) Notation
Numeric notation uses a three-digit (or four-digit with special permissions) octal number. Each digit represents the permissions for owner, group, and others respectively. This is the most common format used in documentation and scripts because it is concise and unambiguous.
chmod 755 deploy.sh # rwxr-xr-x
chmod 644 config.json # rw-r--r--
chmod 600 .env # rw-------
chmod 700 scripts/ # rwx------Symbolic Notation
Symbolic notation uses letters and operators to modify permissions. It is more readable and is especially useful when you want to change a specific permission without affecting others. The format is [who][operator][permission], where who is u (user/owner), g (group), o (others), or a (all), and the operator is + (add), - (remove), or = (set exactly).
chmod u+x script.sh # Add execute permission for owner
chmod g-w config.json # Remove write permission for group
chmod o-rwx secret.key # Remove all permissions for others
chmod a+r README.md # Add read permission for everyone
chmod u=rwx,g=rx,o=rx app # Set exact permissions (equivalent to 755)
chmod +x deploy.sh # Add execute for all (shorthand for a+x)Numeric notation is best when you want to set all permissions at once. Symbolic notation shines when you need to modify a single permission without knowing or changing the rest. In practice, most developers use numeric notation for deployment scripts and symbolic notation for quick one-off changes.
Common Permission Patterns
Certain permission combinations appear over and over again in real-world Linux environments. Here is a reference table of the most common patterns and when to use each:
| Permission | Symbolic | Use Case |
|---|---|---|
| 644 | rw-r--r-- | Regular files (HTML, CSS, JS, images). Owner can edit, everyone else can read. |
| 755 | rwxr-xr-x | Executable files and directories. Owner has full access, others can read and execute/traverse. |
| 600 | rw------- | Private files: SSH keys, .env files, database credentials. Owner only. |
| 700 | rwx------ | Private directories and executable scripts that only the owner should access. |
| 400 | r-------- | Read-only sensitive files. Often used for SSL private keys and authorized_keys. |
| 777 | rwxrwxrwx | Full access for everyone. Almost never appropriate — a major security risk. |
| 775 | rwxrwxr-x | Shared group directories where group members need full access. |
| 664 | rw-rw-r-- | Shared group files where group members need write access. |
Using the chmod Command
The chmod (change mode) command is the primary tool for modifying file permissions in Linux. It accepts both numeric and symbolic notation and supports a variety of options for fine-grained control.
Basic Usage
# Set permissions using numeric notation
chmod 755 deploy.sh
# Add execute permission for the owner
chmod u+x script.sh
# Remove write permission for group and others
chmod go-w sensitive-config.yaml
# Set exact permissions for all categories
chmod u=rwx,g=rx,o= private-dir/Recursive Permission Changes
The -R flag applies permission changes recursively to all files and subdirectories within a directory. This is commonly used when setting up web server directories or fixing permissions across an entire project.
# Set permissions recursively on a directory
chmod -R 755 /var/www/html/
# A more nuanced approach: different permissions for files and directories
# Set directories to 755 and files to 644
find /var/www/html -type d -exec chmod 755 {} \;
find /var/www/html -type f -exec chmod 644 {} \;Caution: Using chmod -R 755 on a directory sets the execute bit on every file inside it, which is usually not what you want. The find-based approach above is the recommended method for recursively setting permissions, because it distinguishes between files (which usually should not be executable) and directories (which need the execute bit to be traversable).
Commonly Used chmod Commands
# Make a script executable
chmod +x deploy.sh
# Protect a private key file
chmod 600 ~/.ssh/id_rsa
# Lock down a .env file
chmod 600 .env
# Make a directory accessible only to the owner
chmod 700 ~/private/
# Allow group members to read and write shared files
chmod 664 shared-document.txt
# Remove all permissions for others on an entire directory tree
chmod -R o-rwx project/Special Permissions
Beyond the standard read, write, and execute permissions, Linux supports three special permission bits that provide additional access control capabilities. These are represented by a fourth leading digit in the numeric notation.
SUID (Set User ID) — 4000
When the SUID bit is set on an executable file, the program runs with the permissions of the file's owner, not the user who executed it. This is how commands like passwd work — the passwd binary is owned by root and has SUID set, allowing regular users to change their own passwords (which requires writing to /etc/shadow, a root-owned file).
# Set SUID on a file
chmod 4755 /usr/bin/myapp
# View SUID: the 's' replaces 'x' in the owner execute position
$ ls -la /usr/bin/passwd
-rwsr-xr-x 1 root root 68208 Mar 15 10:00 /usr/bin/passwdSGID (Set Group ID) — 2000
When set on an executable file, SGID causes the program to run with the permissions of the file's group. When set on a directory, SGID is even more useful: any new files or subdirectories created inside will automatically inherit the directory's group ownership, rather than the creating user's primary group. This is invaluable for shared project directories.
# Set SGID on a shared directory
chmod 2775 /opt/shared-project/
# Now any file created inside inherits the 'developers' group
$ ls -la /opt/shared-project/
drwxrwsr-x 2 root developers 4096 Mar 15 10:00 .
$ touch /opt/shared-project/newfile.txt
$ ls -la /opt/shared-project/newfile.txt
-rw-r--r-- 1 alice developers 0 Mar 15 10:01 newfile.txtSticky Bit — 1000
The sticky bit, when set on a directory, prevents users from deleting or renaming files they do not own, even if they have write permission on the directory. The classic example is /tmp, which is world-writable but has the sticky bit set so that users can only delete their own temporary files.
# Set sticky bit on a shared directory
chmod 1777 /tmp/shared/
# View sticky bit: the 't' replaces 'x' in the others execute position
$ ls -la /
drwxrwxrwt 18 root root 4096 Mar 15 10:00 tmpTip: When viewing permissions with ls -la, special permissions replace the execute character: s in the owner position means SUID, s in the group position means SGID, and t in the others position means sticky bit. If the underlying execute permission is not set, you will see uppercase S or T instead, indicating the special bit is set but execute is not.
Security Best Practices
File permissions are a critical layer of defense on any Linux system. Misconfigured permissions are one of the most common security vulnerabilities, often leading to unauthorized data access, privilege escalation, and system compromise. Follow these guidelines to keep your systems secure:
Never Use chmod 777
Setting permissions to 777gives every user on the system full read, write, and execute access to the file or directory. This is almost never the correct solution. When developers encounter a "permission denied" error, the temptation to chmod 777is strong — but it is the equivalent of removing the lock from your front door because you lost your key. Instead, identify which specific user or group needs access and grant only the minimum permissions required.
Apply the Principle of Least Privilege
Every file and directory should have the most restrictive permissions that still allow it to function correctly. Start with minimal permissions and add more only when needed. If a file only needs to be read by the web server, 644 is sufficient. If a directory only needs to be accessed by the owner, 700 is appropriate. When in doubt, restrict first and loosen only when necessary.
Web Server File Permission Guidelines
Web servers like Nginx and Apache typically run as a dedicated user (e.g., www-data or nginx). The recommended permissions for web content are:
- Directories:
755— The web server can traverse and read, but only the owner can modify. - Static files (HTML, CSS, JS, images):
644— Readable by all, writable only by the owner. - Configuration files with secrets:
600or640— Restrict access to the owner (and optionally the group). - Upload directories:
755with the web server user as owner. Never777.
Consider generating strong passwords for your server credentials using a Password Generator to complement proper file permissions with strong authentication.
Common Permission Scenarios for Developers
Here are the most frequently encountered permission scenarios in day-to-day development work, along with the correct permissions for each:
Web Server Document Root
# Set ownership to your deploy user and web server group
sudo chown -R deploy:www-data /var/www/myapp/
# Directories: owner full access, group and others can read/traverse
find /var/www/myapp -type d -exec chmod 755 {} \;
# Files: owner can read/write, group and others can read
find /var/www/myapp -type f -exec chmod 644 {} \;
# Writable directories (uploads, cache): group can write
chmod 775 /var/www/myapp/storage/
chmod 775 /var/www/myapp/cache/SSH Keys and Configuration
SSH is extremely strict about file permissions. If your key files have permissions that are too open, SSH will refuse to use them. These are the required permissions:
# SSH directory itself
chmod 700 ~/.ssh
# Private keys (id_rsa, id_ed25519, etc.)
chmod 600 ~/.ssh/id_rsa
chmod 600 ~/.ssh/id_ed25519
# Public keys
chmod 644 ~/.ssh/id_rsa.pub
# authorized_keys file
chmod 600 ~/.ssh/authorized_keys
# SSH config file
chmod 600 ~/.ssh/config
# known_hosts
chmod 644 ~/.ssh/known_hostsImportant: If you see the error WARNING: UNPROTECTED PRIVATE KEY FILE! followed by Permissions 0644 for '~/.ssh/id_rsa' are too open, it means your private key is readable by others. Fix it immediately with chmod 600 ~/.ssh/id_rsa.
Executable Scripts and Deployment
# Shell scripts that need to be executable
chmod 755 deploy.sh
chmod 755 backup.sh
chmod 755 run-tests.sh
# Alternatively, add execute permission to an existing script
chmod +x deploy.sh
# CI/CD scripts in a project
chmod 755 scripts/*.shEnvironment and Configuration Files
Environment files (.env) and configuration files containing secrets (database passwords, API keys, tokens) must be locked down. If these files are readable by unauthorized users, your entire application is compromised.
# .env files: owner read/write only
chmod 600 .env
chmod 600 .env.production
chmod 600 .env.local
# Database configuration with credentials
chmod 600 config/database.yml
# SSL/TLS certificates
chmod 600 /etc/ssl/private/server.key
chmod 644 /etc/ssl/certs/server.crtAlways verify the integrity of your configuration files. If you store hashed versions of sensitive values, you can use a Hash Generator to compute and verify checksums to ensure files have not been tampered with.
Calculate Permissions with BeautiCode
Memorizing numeric permission codes can be tedious, especially for less common combinations or when special permission bits are involved. BeautiCode's Chmod Calculator makes it easy to convert between numeric and symbolic notation, visualize permission bits, and generate the exact chmodcommand you need — all directly in your browser with no installation required.
Simply check the permission boxes for owner, group, and others, and the tool instantly shows you the numeric code, the symbolic representation, and the corresponding chmod command. You can also enter a numeric code and see which permission checkboxes light up. It supports special permission bits (SUID, SGID, Sticky Bit) as well.
- Chmod Calculator — Convert between numeric and symbolic chmod notation instantly.
- Password Generator — Generate strong passwords for your server accounts and services.
- Hash Generator — Compute MD5, SHA-256, and other hashes for file integrity verification.
Pro tip: Bookmark the Chmod Calculator for those moments when you are SSH'd into a production server and need to quickly figure out the right permission code. All processing happens client-side, so it works even on slow connections and never transmits your data to any server.
Frequently Asked Questions
What is the difference between chmod 755 and chmod 644?
chmod 755 (rwxr-xr-x) gives the owner full read, write, and execute permissions, while group and others get read and execute. This is used for directories and executable files like shell scripts. chmod 644 (rw-r--r--) gives the owner read and write permissions, while group and others get read-only access. This is the standard permission for regular, non-executable files like HTML, CSS, configuration files, and images.
Why does SSH reject my key with "permissions are too open"?
SSH enforces strict permission checks on private key files to prevent unauthorized access. If your private key file (e.g., ~/.ssh/id_rsa) is readable by group or others (permissions like 644 or 664), SSH will refuse to use it. The fix is simple: run chmod 600 ~/.ssh/id_rsa to restrict access to the owner only. The ~/.ssh directory itself should be 700.
When should I use chmod -R (recursive)?
Use chmod -R when you need to apply the same permissions to an entire directory tree. However, be cautious: applying chmod -R 755 sets the execute bit on all files, which is rarely desired. The best practice is to use find to apply different permissions to files (644) and directories (755) separately. Only use chmod -R with symbolic notation when adding or removing a specific permission, such as chmod -R o-rwx project/.
What permissions should my .env file have?
Your .env file should always be set to 600 (rw-------), meaning only the file owner can read and write it. This file typically contains database passwords, API keys, secret tokens, and other sensitive credentials. If deployed on a server where the application runs as a different user, use 640and ensure the application user is in the file's group. Never commit .env files to version control, and never set their permissions to 644 or higher.
How do I check the current permissions of a file?
Use ls -la filename to view the symbolic permissions, owner, and group of a file. For a numeric representation, use stat -c "%a %n" filename on Linux or stat -f "%Lp %N" filename on macOS. The stat command is particularly useful in scripts where you need to programmatically check or compare permission values. You can also use the Chmod Calculator to decode any numeric permission code into its human-readable symbolic form.
Related Articles
How to Generate Secure Passwords in 2026: A Complete Guide
Learn why strong passwords matter and how to generate secure passwords using entropy, length, and complexity. Includes practical tips and free tools.
2026-03-23 · 8 min readData FormatsJSON vs YAML: When to Use What — A Developer's Guide
Compare JSON and YAML formats with syntax examples, pros and cons, and use case recommendations for APIs, configs, and CI/CD pipelines.
2026-03-23 · 10 min read