Tutorial

Linux File Permissions Explained: chmod, chown, and Why 755 vs 644 Matters

March 20, 2026

Back to Blog

File permissions are the foundation of Linux security. They control who can read, write, and execute every file and directory on your system. Misconfigured permissions are one of the most common causes of security vulnerabilities, "Permission denied" errors, and website malfunctions on Linux servers.

If you have ever wondered why your web server returns a 403 Forbidden error, why a script will not execute, or what those mysterious numbers like 755 and 644 mean, this guide will give you a thorough understanding of Linux file permissions with practical, real-world examples.

The Permission Model: Users, Groups, and Others

Every file and directory in Linux has three sets of permissions assigned to three categories of users:

Owner (u)
The user who created the file
Group (g)
Users in the file's group
Others (o)
Everyone else on the system

Each category can have three types of permissions:

PermissionSymbolNumericFor FilesFor Directories
Readr4View file contentsList directory contents (ls)
Writew2Modify file contentsCreate/delete files in directory
Executex1Run as a programEnter the directory (cd)
None-0No accessNo access

Reading Permission Output

When you run ls -la, the first column shows the permission string:

$ ls -la /home/deploy/
drwxr-xr-x 5 deploy deploy 4096 Mar 17 10:00 .
drwxr-xr-x 4 root root 4096 Mar 17 09:00 ..
-rw------- 1 deploy deploy 220 Mar 17 09:00 .bash_logout
-rw-r--r-- 1 deploy deploy 3771 Mar 17 09:00 .bashrc
drwx------ 2 deploy deploy 4096 Mar 17 10:00 .ssh
-rwxr-xr-x 1 deploy deploy 512 Mar 17 10:00 script.sh
-rw-rw---- 1 deploy www 1024 Mar 17 10:00 shared.txt

Let us break down the permission string -rwxr-xr-x:

- rwx r-x r-x
| | | |
| | | +-- Others: read + execute (5)
| | +------- Group: read + execute (5)
| +------------ Owner: read + write + execute (7)
+--------------- Type: - = file, d = directory, l = link

Numeric: 755

Numeric (Octal) Notation

The numeric system is the most common way to set permissions. Each permission has a value (r=4, w=2, x=1), and you add them up for each category:

NumberPermissionBinaryMeaning
0---000No permissions
1--x001Execute only
2-w-010Write only
3-wx011Write + execute
4r--100Read only
5r-x101Read + execute
6rw-110Read + write
7rwx111Full permissions
755
Standard directory permission
644
Standard file permission
600
Private config files
700
Private directories

chmod: Changing Permissions

The chmod command changes file permissions. You can use either numeric or symbolic notation:

Numeric Mode

# Set standard web file permissions
$ chmod 644 index.html # rw-r--r-- (owner reads/writes, everyone reads)

# Set standard web directory permissions
$ chmod 755 public_html/ # rwxr-xr-x (owner full, everyone reads/enters)

# Set private file (SSH keys, config files)
$ chmod 600 .ssh/id_ed25519 # rw------- (owner only)

# Set executable script
$ chmod 755 deploy.sh # rwxr-xr-x (owner full, everyone executes)

# Set private directory
$ chmod 700 .ssh/ # rwx------ (owner only)

Symbolic Mode

# Add execute permission for owner
$ chmod u+x script.sh

# Remove write permission from group and others
$ chmod go-w config.php

# Set exact permissions for all
$ chmod u=rwx,g=rx,o=rx directory/

# Add read permission for everyone
$ chmod a+r readme.txt

# Recursive: set all files in a directory
$ chmod -R 755 public_html/

chown: Changing Ownership

The chown command changes the owner and/or group of a file:

# Change owner
$ sudo chown deploy index.html

# Change owner and group
$ sudo chown deploy:www-data index.html

# Change only the group
$ sudo chgrp www-data uploads/

# Recursive: change ownership of entire directory tree
$ sudo chown -R deploy:www-data /home/deploy/public_html/

# Verify the change
$ ls -la index.html
-rw-r--r-- 1 deploy www-data 5120 Mar 17 10:00 index.html

Directory vs File Permissions

Permissions behave differently for files and directories. This distinction trips up many administrators:

PermissionOn a FileOn a Directory
r (read)Can view file contentsCan list files in the directory
w (write)Can modify the fileCan create, rename, or delete files inside
x (execute)Can run as a programCan enter the directory (cd into it)
Common Gotcha: Directory Execute Permission
A directory needs x (execute) permission for anyone to enter it. Without x, even if you have r (read), you can list filenames but cannot access the files inside. Without r, you can enter the directory if you know the exact filename, but you cannot list its contents. This is why directories typically use 755 or 700.

Web Server Permission Patterns

Getting permissions right for web servers is critical. The web server process (Nginx/Apache) typically runs as a specific user (like www-data or a per-user PHP-FPM pool user), and it needs to read your files to serve them.

Standard Web Hosting Permissions

# Set ownership: user owns, web server group
$ sudo chown -R deploy:www-data /home/deploy/public_html/

# Directories: owner full, group read+enter, others read+enter
$ find /home/deploy/public_html/ -type d -exec chmod 755 {} \;

# Files: owner read+write, group read, others read
$ find /home/deploy/public_html/ -type f -exec chmod 644 {} \;

# Upload directories: web server needs write access
$ chmod 775 /home/deploy/public_html/uploads/

# Config files: owner only (contains database passwords!)
$ chmod 600 /home/deploy/public_html/wp-config.php
$ chmod 600 /home/deploy/public_html/.env

Here is a complete reference for common web server file types:

File TypePermissionReason
HTML, CSS, JS, images644Everyone needs to read, only owner edits
PHP files644PHP-FPM reads them, owner edits
Directories755Everyone needs to traverse, only owner creates files
Upload directories775Web server group needs to write uploaded files
Config files (.env, wp-config)600Contains passwords, owner only
SSH keys600SSH refuses to use keys with loose permissions
.ssh directory700SSH requires strict directory permissions
Cron scripts755Need execute permission to run
Log files640Owner writes, group (admin) reads, no others

Special Permissions: SUID, SGID, Sticky Bit

Beyond the basic rwx permissions, Linux has three special permission bits that provide additional security and functionality:

SUID (Set User ID) — 4xxx

When a file with SUID is executed, it runs with the file owner's permissions, not the executor's. This is how regular users can change their passwords — the passwd command has SUID set to run as root.

$ ls -la /usr/bin/passwd
-rwsr-xr-x 1 root root 68208 passwd
# Note the 's' instead of 'x' in owner execute

$ chmod 4755 special_program

SGID (Set Group ID) — 2xxx

On a file, SGID makes it run with the file's group permissions. On a directory, new files created inside inherit the directory's group, not the creator's default group.

# Shared project directory
$ chmod 2775 /shared/project/
# New files inherit the 'project' group

Sticky Bit — 1xxx

On a directory, the sticky bit prevents users from deleting files they do not own, even if they have write permission to the directory. The classic example is /tmp.

$ ls -la / | grep tmp
drwxrwxrwt 18 root root tmp
# Note the 't' — sticky bit is set

$ chmod 1777 /tmp

Finding Special Permissions

# Find all SUID files
$ find / -perm -4000 -type f 2>/dev/null
/usr/bin/passwd
/usr/bin/sudo
/usr/bin/chfn

# Find all SGID files
$ find / -perm -2000 -type f 2>/dev/null

umask: Default Permission Control

The umask determines the default permissions for newly created files and directories. It works by subtracting permissions from the maximum:

# Check current umask
$ umask
0022

# With umask 0022:
# New files: 666 - 022 = 644 (rw-r--r--)
# New directories: 777 - 022 = 755 (rwxr-xr-x)

$ touch newfile.txt
$ ls -la newfile.txt
-rw-r--r-- 1 deploy deploy 0 Mar 17 10:00 newfile.txt

$ mkdir newdir
$ ls -la | grep newdir
drwxr-xr-x 2 deploy deploy 4096 Mar 17 10:00 newdir
umaskNew File DefaultNew Dir DefaultUse Case
0022644 (rw-r--r--)755 (rwxr-xr-x)Standard default
0027640 (rw-r-----)750 (rwxr-x---)More restrictive
0077600 (rw-------)700 (rwx------)Private files
0002664 (rw-rw-r--)775 (rwxrwxr-x)Group collaboration

Troubleshooting Common Permission Problems

Problem 1: "Permission denied" for Web Files

Symptom: Your website shows 403 Forbidden or PHP files download instead of executing.
# Check the entire path has execute permission
$ namei -l /home/deploy/public_html/index.php
f: /home/deploy/public_html/index.php
drwxr-xr-x root root /
drwxr-xr-x root root home
drwx------ deploy deploy deploy <-- Problem! Others cannot enter
drwxr-xr-x deploy deploy public_html
-rw-r--r-- deploy deploy index.php

# Fix: allow others to enter the home directory
$ chmod 711 /home/deploy/ # rwx--x--x (enter but not list)

Problem 2: SSH Refuses Key Authentication

Symptom: SSH falls back to password auth even though your key is in authorized_keys.
# SSH is very strict about permissions. Fix all of these:
$ chmod 700 ~/.ssh
$ chmod 600 ~/.ssh/authorized_keys
$ chmod 600 ~/.ssh/id_ed25519 # Private key
$ chmod 644 ~/.ssh/id_ed25519.pub # Public key
$ chmod 644 ~/.ssh/known_hosts

# Home directory must not be writable by group or others
$ chmod 755 ~ # or 750, or 700

Problem 3: Cannot Upload Files via Web Application

Symptom: File uploads fail with "Unable to create directory" or similar errors.
# Check who the web server runs as
$ ps aux | grep php-fpm
deploy 1234 ... php-fpm: pool deploy

# The upload directory needs write access for the web server
$ sudo chown -R deploy:www-data /home/deploy/public_html/uploads/
$ chmod 775 /home/deploy/public_html/uploads/

Permission Audit: Finding Security Issues

# Find world-writable files (security risk!)
$ find /home/ -perm -0002 -type f 2>/dev/null

# Find world-writable directories (excluding tmp and proc)
$ find / -perm -0002 -type d ! -path "/proc/*" ! -path "/tmp/*" 2>/dev/null

# Find files with no owner (orphaned files)
$ find / -nouser -o -nogroup 2>/dev/null

# Find SUID/SGID executables (potential privilege escalation)
$ find / -perm /6000 -type f 2>/dev/null

# Find files readable by everyone containing potential secrets
$ find /home/ -name ".env" -perm -004 2>/dev/null
$ find /home/ -name "wp-config.php" -perm -004 2>/dev/null

Quick Reference: Permission Cheat Sheet

ScenariochmodWhat It Means
Web file (HTML, CSS, JS, PHP)644Owner reads/writes, everyone reads
Web directory755Owner full, everyone reads/enters
Upload directory775Owner and group full, others read/enter
Config file (.env, wp-config)600Owner only, no one else
SSH private key600Owner only (SSH enforces this)
.ssh directory700Owner only (SSH enforces this)
Executable script755Owner full, everyone executes
Private home directory700Owner only
Shared home (web accessible)711Owner full, others can enter (not list)
Log file640Owner writes, group reads

Panelica: Automatic Permission Management

Panelica enforces correct file permissions automatically through its 5-layer isolation architecture, eliminating the entire category of permission-related security issues:

  • Dedicated UID/GID per user — each user gets a unique system user and group, preventing cross-user file access
  • Home directories set to 700 — users cannot see or access each other's files by default
  • UserContextService — all file operations go through a service that enforces correct ownership. Root writes a temporary file, then chowns it to the correct user, preventing privilege escalation
  • Per-user PHP-FPM pools — each user's PHP processes run under their own UID, so even if a PHP application is compromised, it can only access that user's files
  • open_basedir enforcement — PHP is restricted to the user's home directory, preventing directory traversal attacks at the PHP level
  • Namespace isolation — users operate in isolated PID and mount namespaces, making other users' processes and files invisible at the kernel level
Permissions Done Right, Automatically
With Panelica, you never need to manually run chmod or chown on web files. The panel creates directories with correct ownership, sets proper permissions on configuration files, and isolates users from each other through five independent security layers — from Unix permissions to kernel namespaces.
Share: