Skip to main content

Linux Permission Codes (Numeric / Octal)

Linux permission codes like 644 and 755 are an octal shorthand for the read/write/execute bits on a file or directory. On a WordPress VPS, understanding them prevents the two most common mistakes: breaking the site with overly strict permissions, or "fixing" problems with unsafe 777.

Quick Summary
  • Permissions are three digits: owner/group/others.
  • Each digit is a sum of r=4, w=2, x=1.
  • Common baseline: files 644, directories 755.
  • Directories need x to be accessible (traversal).
  • Prefer targeted fixes; avoid blanket chmod -R without a plan.

The mental model​

Permissions are evaluated against three user classes:

  • owner (user)
  • group
  • others

Each class gets a sum of:

  • read (r) = 4
  • write (w) = 2
  • execute (x) = 1

So one digit describes one class. Three digits describe owner/group/others.

permission-code-structure.txt
XYZ
X = owner
Y = group
Z = others

The 4-2-1 math (rwx -> octal)​

rwx-to-octal-cheat.txt
rwx = 4 + 2 + 1 = 7
rw- = 4 + 2 + 0 = 6
r-x = 4 + 0 + 1 = 5
r-- = 4 + 0 + 0 = 4
--- = 0

Read permissions with ls -l​

ls -l shows permissions in the symbolic form:

ls-l-symbolic-example.txt
-rw-r--r-- 1 siteuser www-data 4180 Mar 1 12:00 wp-config.php
drwxr-xr-x 5 siteuser www-data 4096 Mar 1 12:00 wp-content

Breakdown:

  • first char: file type (- file, d directory)
  • next 3: owner permissions
  • next 3: group permissions
  • next 3: others permissions

Files vs directories (why x matters)​

The x bit means different things:

  • on files: execute (run it as a program)
  • on directories: enter/traverse the directory

This is why a directory often needs x even if you are not "executing" anything.

Example:

  • chmod 644 wp-content is usually wrong (it removes directory execute and breaks traversal)
  • chmod 755 wp-content is a common baseline

Common permission codes and what they mean​

CodeSymbolicTypical meaningCommon use on a WordPress VPS
600rw-------owner read/write onlysecrets: private keys, restrictive configs
640rw-r-----owner read/write, group readwp-config.php in group-based models
644rw-r--r--owner read/write, everyone readmost files (PHP, CSS, images)
700rwx------owner full, nobody elseprivate directories
750rwxr-x---owner full, group enter/readshared dirs (owner + group)
755rwxr-xr-xowner full, everyone enter/readmost directories
warning

Avoid 777. It grants world-write and usually indicates an ownership/group problem. Fix identity and group strategy instead.

Converting quickly (examples)​

Example: 755​

  • owner 7 = rwx
  • group 5 = r-x
  • others 5 = r-x

This is a common directory baseline.

Example: 644​

  • owner 6 = rw-
  • group 4 = r--
  • others 4 = r--

This is a common file baseline.

Worked examples (common modes)​

Use this section when you want to sanity check a mode quickly.

ModeSymbolicTypical use
600rw-------secrets and restrictive configs
640rw-r-----secret file readable by a trusted group
644rw-r--r--most WordPress files
664rw-rw-r--group-collaboration file (use sparingly)
700rwx------private directory
750rwxr-x---shared directory (owner + group)
755rwxr-xr-xmost directories
775rwxrwxr-xgroup-writable directory (uploads/cache in group model)

Decode 640​

  • owner 6 = rw-
  • group 4 = r--
  • others 0 = ---

This is useful when a file contains secrets but you want a trusted group to read it.

Decode 775​

  • owner 7 = rwx
  • group 7 = rwx
  • others 5 = r-x

This is commonly used for group-writable directories in a shared group model.

warning

Do not apply 775 everywhere. Only use group write on directories that must be writable (uploads, caches, runtime dirs).

Numeric vs symbolic chmod​

Numeric chmod sets all three classes at once (owner/group/others). Symbolic chmod modifies specific bits and is often safer for incremental changes.

Examples:

chmod-numeric-vs-symbolic.sh
# Numeric: set exact mode
chmod 755 wp-content
chmod 644 wp-config.php

# Symbolic: add or remove bits relative to current
chmod g+w wp-content/uploads
chmod o-w wp-content/uploads
chmod u+x /usr/local/bin/deploy.sh

umask and default permissions​

Default permissions on new files and directories are influenced by umask.

Typical default behavior on many servers:

  • file created with base 666 becomes 644 (umask 022)
  • directory created with base 777 becomes 755 (umask 022)

Check your umask:

check-umask.sh
umask

Lab to see it in action:

lab-umask-defaults.sh
rm -rf /tmp/umask-lab
mkdir -p /tmp/umask-lab
cd /tmp/umask-lab

touch file.txt
mkdir dir

stat -c '%A %a %n' file.txt dir

WordPress path guide (practical)​

This table is a starting point for a typical Linux WordPress install. Adjust to your stack and ownership model.

PathTypical modeNotes
WordPress directories755default directory baseline
WordPress files644default file baseline
wp-content/uploads/755 or 775775 if group model and web user needs write
cache directories755 or 775only if the cache plugin needs write
wp-config.php600 or 640secrets file; keep tight
.htaccess (Apache/OLS)644may be updated by WordPress depending on settings
warning

Some plugins attempt to write to places they should not. Prefer correcting the plugin or choosing a different plugin over widening permissions globally.

Safer bulk changes (dry-run first)​

Before running a bulk chmod on production, list what will be affected.

dry-run-list-top-level-wp-tree.sh
cd /var/www/html
find . -maxdepth 2 -type d -print | sed -n '1,50p'

Then apply the smallest change that fixes the problem.

WordPress practical defaults​

These are patterns, not laws. Your stack (Nginx/Apache/OLS), deploy model, and PHP handler matter.

Common baseline:

  • directories: 755
  • files: 644
  • wp-config.php: tighter (commonly 600 or 640)

Why wp-config.php is special:

  • it contains database credentials and secrets
  • it should not be writable by the world
  • it should not be readable by unintended users

Apply permissions safely​

Single path examples​

chmod-examples.sh
chmod 755 wp-content
chmod 644 wp-config.php

# Show what you changed
stat -c '%A %a %U:%G %n' wp-content wp-config.php

Normalize a WordPress tree (directories vs files)​

If you need to normalize a tree, do it in a controlled way:

  1. set directories to 755
  2. set files to 644
  3. tighten wp-config.php
normalize-wp-perms-example.sh
cd /var/www/html

# Directories
find . -type d -print0 | xargs -0 chmod 755

# Files
find . -type f -print0 | xargs -0 chmod 644

# Tighten secrets
chmod 600 wp-config.php
warning

find + chmod can break a production site if you run it in the wrong directory. Always confirm the path first (pwd, ls, realpath) and consider testing on staging.

Ownership vs permissions (do not skip this)​

Many "permission" problems are actually ownership problems.

If your deploy user is siteuser and your web server runs as www-data, decide a model:

  • strict model: only specific directories are writable by the web user
  • group model: use siteuser:www-data and group write where needed

Use id to confirm group membership:

check-user-groups.sh
id -nG siteuser
id -nG www-data || true

Verify with stat and namei​

stat is more precise than ls -l when you are debugging.

stat-perms-owner-group.sh
stat -c '%A %a %U:%G %n' wp-config.php
stat -c '%A %a %U:%G %n' wp-content/uploads

Example output:

example-stat-output.txt
-rw------- 600 siteuser:www-data wp-config.php
drwxr-xr-x 755 siteuser:www-data wp-content/uploads

If access fails, verify every parent directory is traversable:

namei-check-path-permissions.sh
namei -l wp-content/uploads

Runbook: fix a WordPress "uploads not writable" incident​

This runbook assumes you already confirmed disk space and inode space are OK.

  1. Identify the web/PHP user.
  2. Check ownership and perms on wp-content/uploads.
  3. Fix ownership/group model.
  4. Verify by creating a test file.
uploads-incident-checks.sh
cd /var/www/html

ls -ld wp-content/uploads
stat -c '%A %a %U:%G %n' wp-content/uploads

sudo -u www-data bash -lc 'touch wp-content/uploads/.perm_test && rm -f wp-content/uploads/.perm_test' || true
warning

Do not "fix" this with chmod -R 777. If the web user cannot write, align ownership and group access instead.

Troubleshooting matrix​

SymptomLikely causeCheckSafer fix
Uploads failwrong owner/group on uploadsls -ld wp-content/uploadsset correct owner/group; ensure directory has x
Site shows 403missing directory traversenamei -l /var/www/htmlrestore x on each directory
PHP files download instead of executewrong server/PHP handlercheck server config/logsfix handler; perms are not the real issue
SSH deploy works, browser failsdifferent user contextsid; sudo -u www-data idgroup model or targeted writable dirs

Common mistakes​

Mistake: making directories 644​

Symptom: "Permission denied" when WordPress tries to access files inside. Fix: directories need x.

Mistake: using 777 to "fix" uploads​

Symptom: uploads work, but you introduced a security risk. Fix: correct ownership and group membership.

Mistake: recursive chmod on the wrong path​

Symptom: permissions on system dirs or home dirs break unrelated services. Fix: use explicit paths and a restore plan.

Lab: decode and apply​

  1. Decode these codes into symbolic form:
  • 600
  • 640
  • 644
  • 750
  • 755
  1. Create a test folder and apply them:
lab-create-test-files.sh
mkdir -p /tmp/perm-lab/dir
echo hello >/tmp/perm-lab/file.txt

chmod 755 /tmp/perm-lab/dir
chmod 644 /tmp/perm-lab/file.txt

ls -ld /tmp/perm-lab/dir
ls -l /tmp/perm-lab/file.txt
  1. Observe what changes when you remove x from a directory:
lab-remove-directory-execute.sh
chmod 644 /tmp/perm-lab/dir
ls -ld /tmp/perm-lab/dir

# This will fail because you cannot traverse the directory.
ls -l /tmp/perm-lab/dir || true

Reference: octal lookup​

0-7 lookup table
octal-lookup.txt
0 ---
1 --x
2 -w-
3 -wx
4 r--
5 r-x
6 rw-
7 rwx

Appendix: special bits (4-digit modes)​

Some modes have a leading digit for special bits (setuid, setgid, sticky). These are not required for basic WordPress operations, but you will see them on system directories.

special-bits-overview.txt
4xxx = setuid
2xxx = setgid
1xxx = sticky bit

If you need these, treat them as a separate topic from basic 644/755.