Security & Privacy

WordPress File Permissions: 644, 755 and When Something Else

chmod 777 makes the error disappear by handing write access to every process on the server. What the three digits mean, the standard WordPress set, and why ownership decides which digit even gets read.

WordPress File Permissions: 644, 755 and When Something Else

The advice is everywhere, and it always sounds certain: run chmod 777 on the folder and the error goes away. It appears under every failed upload, every plugin that cannot save its settings, every update that dies with “destination folder not writable”. The worst part is that it works. The error really does go away.

What also happens: every account and every process on that server can now write to your files. On shared hosting that includes other customers’ sites and whatever a compromised script somewhere on the machine is running as. A world-writable directory is the easiest possible place to drop a PHP backdoor. 777 does not fix the problem, it removes the security that was catching it.

The frustrating truth is that the correct values for WordPress have been the same for about two decades: 755 for directories, 644 for files, something stricter for wp-config.php. When those values produce errors, the permissions are not wrong. The ownership is, and that is a different fix entirely.

This article walks through what the digits mean, why the standard set is what it is, and how to repair a tree that someone already ran 777 over. The calculator below does the octal arithmetic for you: tick the nine boxes, or type an octal or symbolic value, and it keeps all three representations in sync, flags dangerous combinations and hands you the exact chmod command. It runs entirely in your browser and nothing you type leaves the page.

File permissions calculator

Click a permission set together or type it as a number, watch the octal and symbolic spellings stay in sync, and get the right value for every WordPress file, with the reason behind it. Everything is worked out in this browser tab, nothing leaves your browser.

Tick the rights
Owner Group Others

Both spellings say the same thing: one digit or triad each for owner, group and others. A fourth digit in front carries the special bits, and a leading zero is swallowed, 0644 and 644 are the same value.

644 rw-r--r--
WordPress presets
Who is the owner? On modern shared hosting with suEXEC or a PHP-FPM pool, PHP runs as the user who owns your files, so the owner column does almost all the work and Group and Others rarely need any rights at all. On classic mod_php the web server reads your files as its own user, usually www-data, and reaches them through the Group or Others bits. That is why two hardening guides can disagree and both be right: they assume different owners.
The command
chmod 644 file.php
WunderPaint
The Dynamic Design and Automation Studio
WunderPaint is a layered image editor for your WordPress media library. WunderPaint Studio is the same thing in any browser, free and without an account.

Three Digits, Nine Bits

A permission value like 644 is three digits, and each digit is the sum of three bits: read is 4, write is 2, execute is 1. A 7 is all three (4+2+1), a 6 is read and write (4+2), a 5 is read and execute (4+1), a 4 is read only, a 0 is nothing. There are no other legal digits, which is why 778 is not a permission value and the calculator quietly refuses it.

The three digits address three audiences, in order: the owner of the file, the group of the file, and others, meaning every other account on the machine. That last class is bigger than it sounds. On a typical server, “others” includes the mail daemon, the backup agent, every cron job of every other customer, and whatever identity an attacker’s script happens to hold.

The bits also mean different things on a file than on a directory, and this is the detail most explanations skip.

Table of the permission bits r, w and x with their octal values 4, 2 and 1, comparing what each bit does on a file with what it does on a directory: read lists names, write creates and deletes entries, execute enters the directory.

The one that trips everyone up is x on a directory. It does not mean run, it means enter: without it you cannot change into the directory or reach anything inside it, even if you know the exact filename and the file itself is world-readable. That is the entire difference between 644 and 755. A directory at 644 is a locked room you are allowed to read the label on. Directories get the extra 1 in each digit precisely so the same audiences that may read the files can actually reach them.

The reverse detail matters too: w on a directory controls the name table, not the file contents. A user with write on the folder can delete or rename a file inside it even when the file itself is 444. Permissions on the containing directory matter as much as the file’s own bits, which is also why the sticky bit exists (more on that further down).

The Standard WordPress Set

The five presets in the calculator are the whole recommended layout. Directories 755: the owner reads, writes and enters, everyone else reads and enters. Files 644: the owner reads and writes, everyone else reads. Nobody except the owner ever needs write, and nothing needs execute on a file.

Why do group and others get read at all? Because on many stacks the web server that delivers static assets is a different user from the one that owns them. nginx or Apache running as www-data reads your CSS, images and JavaScript through the others digit. Take that 4 away and the assets start returning 403.

wp-config.php is the exception in the strict direction. It holds the database credentials and the authentication keys, and exactly one process needs to read it: PHP. On modern hosting PHP runs as the file owner, so 600 (owner read and write, nothing else) works and gives away nothing. If your host still runs PHP as a separate user, 600 will white-screen the site, and you fall back to 640 with the right group, or 644 as a last resort. Which constants in that file are worth protecting is a topic of its own: wp-config.php explained.

.htaccess stays at 644 because Apache reads it as the server user on every single request, so it must remain world-readable, and WordPress itself rewrites it when you change permalink settings, so the owner keeps write. If a security plugin locks it to 444, permalink changes silently stop reaching the file. What the lines inside it actually do is covered in the htaccess explainer.

The uploads tree is the one place WordPress must create files and directories at request time: any upload can mint a new year and month folder. It still only needs 755, because on a healthy setup the PHP process is the owner. If uploads die with “Unable to create directory wp-content/uploads/2026/08”, the missing piece is almost never a permission digit. Check who owns the uploads folder before touching chmod, and if the message is the generic one, the HTTP error causes are worth ruling out first.

Core agrees with these numbers in its own source. When WordPress writes files through its filesystem API (updates, plugin installs), it uses two constants, defined in wp-admin/includes/file.php if you have not set them yourself:

define( 'FS_CHMOD_DIR', ( fileperms( ABSPATH ) & 0777 | 0755 ) );
define( 'FS_CHMOD_FILE', ( fileperms( ABSPATH . 'index.php' ) & 0777 | 0644 ) );

Read the OR: whatever your WordPress root already has, but at least 755 and 644. And when the upload handler saves a file, it copies the permissions of the folder the file lands in, minus all execute bits:

$stat  = stat( dirname( $new_file ) );
$perms = $stat['mode'] & 0000666;
chmod( $new_file, $perms );

That & 0000666 mask is why uploaded images never carry execute bits. It is also why a 777 uploads folder quietly produces 666 files: world-writable, forever, on every future upload. Wrong permissions propagate themselves.

Ownership Decides Everything

Here is the question the 777 advice never asks: which user is PHP? chmod writes three answers, one per digit, but the kernel reads only one of them per access, and it picks by identity. If the process is the owner, the first digit answers. If it is in the file’s group, the second. Otherwise the third.

Two panels comparing PHP under PHP-FPM, running as the file owner so the owner digit answers every request, with PHP under classic mod_php running as www-data, where only the final others digit applies and 644 leaves PHP read only.

On most current hosting (PHP-FPM pools, suEXEC, LiteSpeed, virtually every managed WordPress host) PHP runs as the same account that owns the files. Updates, uploads and cache writes are all answered by the owner digit, which is 6 or 7 everywhere in the standard set. Group and others never need write. That is exactly why 755 and 644 are enough.

The setup where they are not enough is classic mod_php: PHP embedded in Apache, running as www-data, while the files belong to the account you deploy with. Now PHP is neither owner nor group member and gets the last digit: 4, read only. Every write fails, someone suggests 777, and it works because you just gave write access to literally everyone, which happens to include www-data. That is the whole 777 phenomenon: a correct diagnosis (PHP cannot write) with the most destructive available treatment.

The real fix is one of two moves. Either give the files to the user PHP runs as (chown -R, on a server you control), or move PHP so it runs as the owner (an FPM pool per site, or a request to your host, who has almost certainly already set it up that way). To find out which user PHP actually is, do not guess:

ps -o user= -C php-fpm     # or: -C apache2, -C httpd
stat -c '%U %G' wp-config.php

If the first command’s user and the second command’s owner match, the owner digit is answering and the standard set just works. If they differ, that mismatch is your actual problem, and no chmod value fixes it.

Repairing a Tree After 777

Once someone has run chmod -R 777, or an installer has left random values behind, fix it wholesale. Two commands reset an entire installation to the standard set:

cd /var/www/example.com/htdocs    # your WordPress root
find . -type d -exec chmod 755 {} +
find . -type f -exec chmod 644 {} +
chmod 600 wp-config.php

Three things about these lines. First, the cd matters more than anything else: find recurses through everything below the current directory, so run the pair only from inside the WordPress root, and confirm with pwd and ls wp-config.php that you are where you think you are. Pointed at /, it will happily re-permission the operating system. Second, the {} + ending batches thousands of paths into a few chmod invocations instead of one process per file, which on a large uploads library is the difference between two seconds and several minutes. Third, the order of the two find lines does not matter, because -type d and -type f never overlap.

The calculator prints this pair for you when you use the two directory presets: the -type d line follows whatever octal is currently set, the -type f line stays at 644, and the copy button takes both lines along.

The Execute Bit on PHP Files Does Nothing

A surprising number of tutorials recommend 755 on .php files. The x bit tells the kernel it may load the file as a program through execve. Web PHP never takes that path: mod_php reads the script inside the Apache process, and PHP-FPM receives the path as SCRIPT_FILENAME over FastCGI and opens it like any data file. Both need the read bit only. A PHP file at 644 executes exactly as well as one at 755.

The one place x on a PHP file is real is the command line: a script with a shebang, run directly.

#!/usr/bin/env php
<?php
// now ./script.php works, and this file genuinely needs +x

Inside a WordPress tree that case does not exist, which is why the calculator warns when it sees execute bits on what it takes to be a file. Execute on .php buys you nothing and makes a smuggled-in file marginally more useful to whoever put it there.

The Fourth Digit

Sometimes a value arrives with four digits: 4755, 2775, 1777. The leading digit holds the special bits: setuid (4), setgid (2) and sticky (1). Setuid and setgid on a file mean the program runs with the owner’s or the group’s identity instead of the caller’s. In a web tree that is somewhere between pointless and alarming, and the calculator flags it accordingly.

Two directory uses are legitimate. Setgid on a directory (2775) makes new files inherit the directory’s group instead of the creator’s primary group, which genuinely helps when an SFTP user and the PHP user share a group and both write to the same folder. Sticky on a directory (1777) means only a file’s owner may delete it; that is what keeps users from deleting each other’s files in /tmp. In symbolic notation the special bits ride on the x position of their triplet: s where the x underneath is also set, S where it is not, and t or T in the others triplet for sticky. A three-digit octal like 644 deliberately means “no special bits”, which is why typing one into the calculator clears them.

Strip away the octal and file permissions are one question asked three times: who are you? Owner, group member or stranger, one digit each. Every WordPress permission problem is therefore one of two things. Either the digits are wrong, which the standard set and two find commands repair in under a minute. Or the identity is wrong, which no chmod value can repair and which 777 merely surrenders to.

So the next time a forum thread offers the magic number, translate it: “we do not know which user PHP runs as, so we allow everyone”. You can do better with two commands. Ask ps who runs PHP, ask stat who owns the files. If they match, set 755 and 644 and stop. If they do not, fix the ownership. The digits were never the problem.

WordPress File Permissions: 644, 755 and When Something Else

Table of Contents

Learn it by building something

Every week one thing you can make the same afternoon, from dynamic templates to 3D type. Written down step by step.

One mail a week, and then it ends.
Unsubscribe in one click.

Developer Tools

htaccess Explainer: Reading the File Nobody Reads

Every WordPress site on Apache has an .htaccess, and Apache reads it on every request for every directory in the path. Here is what the WordPress block actually does, why [L] does not mean last, the difference between Redirect and RewriteRule, and which pasted security snippets have done nothing since Apache 2.4.

Troubleshooting

Error Establishing a Database Connection: What WordPress Is Actually Telling You

The message means PHP ran, wp-config.php was read, and the connection to MySQL failed. Nothing more. Here is how to tell a wrong password from a downed server from a host that ran out of connections, and what to do about each.

Troubleshooting

The WordPress White Screen of Death Explained

A white screen with no error message isn't a WordPress bug. It's PHP dying silently mid-request. Here's how to see the real error in minutes and the exact order to check plugins, theme, and memory limits.

Photo Editing

Never Destroy Pixels You Might Want Back: A Working Method

Every edit is either reversible or it is not, and the difference costs nothing at the moment you make it. It shows up later, always at the worst time.

WordPress Images

Clean Up WordPress Media Library Without Breaking Pages

An attachment is a row in wp_posts; its files sit somewhere else, and deleting one does not delete the other. What to measure before you start, why "unused" is so hard to prove, and the order of operations that keeps the site up.

WordPress Images

Image Quality Curve: Why Every Recommended Setting Is Wrong

Quality 80 means one thing in JPEG, another in WebP, and something different again on a screenshot than on a photograph. Here is what the number actually sets, what SSIM can and cannot tell you, and how to find the point where your own file stops getting meaningfully smaller and starts getting visibly worse.

Download the free WunderPaint Plugin for WordPress

The WunderPaint workspace with the layers panel, adjustment sliders, text style presets and the asset library along the bottom

The Image Editor & Design Studio

Everything described here can be done in the browser, on your own site. The live demo runs the full editor with nothing to install.

Free

Chaos Art

Autonomous painters make one-of-a-kind abstract art in 3D space - gestures, art movements, painterly media, and embeds that paint a new original for every visitor.

Pro

Particle Strokes

Paint with swarms of light: twenty-two movements, a stamp you draw yourself, and curves that give a stroke a shape - the swarm keeps painting for a few seconds after you let go.

Pro

City Diorama

Any place on earth as a miniature you could hold: real streets, water and building footprints raised into a 3D diorama - or wrapped around a sphere as your own tiny planet.

Free

Papercut Art

Layered paper pictures with real depth - a photo sliced along its actual depth into up to twenty layers, parametric landscapes, animals and clouds you can shape, letters with real counters, and a look that runs on three dials.

Pro

3D Earth Studio

A hyperrealistic globe - day and night with city lights, live clouds, atmosphere halo, country borders and highlights, click-to-place markers with flight-route arcs, satellite orbits, seamless rotation video and a live website embed.

Free

Mystic Studio

Turn a birth date into wall art - a real natal chart with houses and aspects, the moon of that night, zodiac and Chinese zodiac posters, numerology cards and a synastry wheel for two, in eight artful themes.

Free

Marble Bath

Marble paper on a virtual water bath - drop, rake and comb real Ebru patterns with gestures, flowers and classic recipes, razor-sharp at any size and re-editable as a layer.

Free

Day Ring

Turn a day into a beautiful circular schedule - colour-coded time blocks as arcs around a 24-hour clock, with concentric rings for overlaps, emoji, templates and a legend.

Free

Code Shot

Turn code into a gorgeous, share-ready image - syntax highlighting, editor themes, window frames and diff highlighting - then drop it into your design as a re-editable layer.

Pro

3D Solar System Studio

Build a date-accurate 3D solar system - real planet positions for any date, photoreal textures and one slider from artistic to true scale - then drop it into your design as an editable layer.

Pro

3D Molecule Studio

Build a real 3D molecule - from a curated library, the periodic table or a SMILES string - then style it, measure it and drop it into your design as an editable layer.

Pro

3D Textile Studio

Drop your design onto cloth that behaves like the material you pick: silk falls soft, felt holds its shape, flag fabric snaps in the wind. Hang it, blow it and drape it, then lay the finished drape back into your document as a picture.

Pro

3D Particle Studio

Point the engine at any layer and it becomes a cloud of particles that keeps its colours, flowing through a sphere, a galaxy or your own outline. Keep the frame you like as a still, or embed the running engine so it keeps moving on your page.

Free

Origami

Put your own picture on the paper and watch that very sheet fold itself into a crane or a box. Every step is a station you can stop at and turn around in 3D, which is exactly where printed diagrams leave you alone.

Pro

3D Flip Studio

A hardcover you can leaf through, a limp magazine, a strewn pile of sheets, a sticker peeling off its backing. The curl is real geometry, so the print never slides across the paper.

Free

Handwriting Fonts

Draw the alphabet here or fill in a printed sheet and photograph it. What comes out is a genuine font family, installed into your site and available in every picker.

Pro

Step Guides

Turn any picture into an instruction. Every mark is pinned to a place in the image, so arrows still point at the right thing after the callout has been dragged somewhere else.

Free

Text Art

One studio, sixteen art types: ASCII and emoji art, brick, dice, cube, sticky-note, LED, ceramic and keycap mosaics, word portraits, text flows, silhouettes, element tiles and more.

Free

Photo Mosaic

The classic photomosaic, computed in your browser: your main image emerges from many media-library photos via true structure matching - never a cheap overlay.