File permissions on a WordPress site are one of those things that work fine until they don’t. Set them too loose and anyone on your server can read or modify your files. Set them too tight and plugins stop working, uploads fail, and your site breaks. This guide builds on the basics to give you a complete understanding of Linux file permissions, how to check them, fix them, and automate permission audits across your WordPress installation.
WordPress file permissions security hardening: Understanding Linux File Permissions
Every file and directory on a Linux server has three permission sets: one for the file owner (user), one for the group, and one for everyone else (public/world). Each set uses three bits: read (4), write (2), and execute (1). The permissions are expressed as a three-digit octal number where each digit is the sum of the enabled bits.
Here is what each permission means for files versus directories:
- Read (4): For files, read means you can view the file contents. For directories, it means you can list the directory contents.
- Write (2): For files, write means you can modify the file. For directories, it means you can create, rename, or delete files within the directory.
- Execute (1): For files, execute means you can run the file as a program or script. For directories, it means you can access files inside the directory (cd into it).
Common permission values you will encounter:
- 644: Owner can read and write. Group and public can only read. Standard for files.
- 755: Owner can read, write, and execute. Group and public can read and execute. Standard for directories.
- 600: Owner can read and write. Group and public have no access. Ideal for wp-config.php.
- 640: Owner can read and write. Group can read. Public has no access. Good for wp-config.php on shared hosting.
- 444: Everyone can read. No one can write. Used for files that should never change.
- 777: Everyone can read, write, and execute. Never use this in production.
WordPress file permissions security hardening: Why File Permissions Matter for Security
Every file on a Linux server has three permission levels: owner, group, and public. Each level can have read (4), write (2), and execute (1) permissions. If wp-config.php is world-readable (644 or higher), any other account on a shared hosting server can read your database credentials. If your uploads directory is writable by the web server user, an attacker who uploads a PHP shell can execute code on your server.
Getting permissions right is the foundation of WordPress hardening. Everything else, including firewalls, security plugins, and monitoring, assumes the filesystem itself is locked down.
The Correct WordPress File Permissions
Here are the recommended permissions for a standard WordPress installation:
- All files: 644 (owner can read/write, group and public can only read)
- All directories: 755 (owner can read/write/execute, group and public can read/execute)
- wp-config.php: 600 or 640 (owner only, or owner and group, never 644 or 666)
- .htaccess files: 644 (web server needs to read them)
- wp-content/uploads: 755 (directories), 644 (files) with web server write access for uploads
To apply these permissions, SSH into your server and run:
find /path/to/wordpress -type f -exec chmod 644 {} ;
find /path/to/wordpress -type d -exec chmod 755 {} ;
chmod 600 /path/to/wordpress/wp-config.phpHow to Check Permissions with Terminal Commands
Before fixing permissions, you need to know what they currently are. These commands will show you the current state:
# Check permissions of all files in a directory
ls -la /path/to/wordpress
# Check permissions recursively for specific file types
find /path/to/wordpress -type f -name "*.php" -ls
# Find files with dangerous permissions (777)
find /path/to/wordpress -perm 777 -type f
# Find world-writable directories
find /path/to/wordpress -perm 777 -type d
# Check wp-config.php specifically
ls -la /path/to/wordpress/wp-config.php
# Check .htaccess permissions
ls -la /path/to/wordpress/.htaccessThe output of ls -la shows permissions in the first column, like this: -rw-r–r–. The first character indicates the file type (d for directory, – for file). The next three characters are owner permissions, then group, then public.
How to Fix Permissions with find and chmod
Use the find command combined with chmod to apply correct permissions across your entire WordPress installation. These commands are safe to run on any standard WordPress setup:
# Set all files to 644
find /path/to/wordpress -type f -exec chmod 644 {} ;
# Set all directories to 755
find /path/to/wordpress -type d -exec chmod 755 {} ;
# Secure wp-config.php to 600
chmod 600 /path/to/wordpress/wp-config.php
# Secure wp-config.php on shared hosting (allow group read)
chmod 640 /path/to/wordpress/wp-config.php
# Secure .htaccess files
find /path/to/wordpress -name ".htaccess" -exec chmod 644 {} ;For shared hosting environments where the web server user (www-data, nginx, apache) differs from your FTP user, you may need to keep wp-content/uploads more permissive. In that case, set uploads to 755 (directories) and 644 (files) after ensuring ownership is correct.
Checking Ownership with chown
Permissions control what can be done. Ownership controls who can do it. On most shared hosting setups, your FTP user and the web server user (www-data, nginx, apache) are different. This means wp-content/uploads needs to be writable by the web server, but owned by your FTP user.
The ideal ownership setup:
- All WordPress files owned by your FTP/SFTP user
- wp-content owned by the web server user (or a shared group)
- wp-content/uploads writable by the web server user
# Check current ownership
ls -la /path/to/wordpress
# Change ownership (if you have sudo access)
chown -R user:group /path/to/wordpress
# Change wp-content to be writable by web server
chown -R www-data:www-data /path/to/wordpress/wp-contentIf you cannot change ownership (common on shared hosting), use 755 for directories and 644 for files, and rely on directory hardening to block PHP execution in uploads as an additional safety net.
The Most Common Permission Mistakes
- 777 on wp-content/uploads: Some hosting setups need this for plugin updates, but it means anyone can write to that directory. Use 755 instead and set the correct owner.
- wp-config.php readable by everyone: If your wp-config.php has permissions of 644 or higher, every user on a shared server can see your database name, password, and security keys.
- Executable permission on PHP files in uploads: Even with 644 permissions, if PHP execution is enabled in the uploads directory, an attacker can upload a malicious PHP file and run it. This is where directory hardening comes in.
- Setting files to 755 instead of 644: Files do not need execute permission. Giving execute permission to PHP files in wp-admin or wp-increases the risk of code execution attacks.
- Running WordPress as root: Never run WordPress files owned by root. Use a dedicated system user with minimal privileges.
Dangerous Permissions: Why 777 Is Never the Answer
Permission 777 means any user on the server can read, write, and execute the file or directory. On a shared hosting server, this potentially gives thousands of other accounts access to your files. If even one account on the server is compromised, every 777 directory on that server becomes a target.
When a hosting support agent tells you to use 777, push back. Ask for the specific user or group that needs write access and set the correct ownership instead. If that is not possible, use 775 (group write) as an absolute maximum, and never on wp-config.php or .htaccess.
wp-config.php Protection
wp-config.php is the single most sensitive file in any WordPress installation. It contains your database credentials, authentication keys and salts, and core configuration settings. If this file is world-readable, every user on your shared hosting server can extract your database password.
Set wp-config.php to 600 or 640. Permission 600 means only the file owner can read or write it. Permission 640 allows the group to read it, which is useful when your FTP user and web server user belong to the same group. Never use 644 or higher.
# For single-user setups
chmod 600 /path/to/wordpress/wp-config.php
# For shared hosting with group access
chmod 640 /path/to/wordpress/wp-config.phpIn addition to permissions, you should also move wp-config.php above the web root if possible. WordPress looks for wp-config.php in the parent directory before checking the root, so moving it one level up adds another layer of protection.
Permission Audit Script
Run this script periodically to audit your WordPress file permissions. It checks for dangerous permissions and reports findings:
#!/bin/bash
# WordPress Permission Audit Script
# Save as wp-perm-audit.sh and run: bash wp-perm-audit.sh /path/to/wordpress
WP_PATH="${1:-.}"
echo "=== WordPress Permission Audit ==="
echo "Scanning: $WP_PATH"
echo ""
# Check for 777 permissions
echo "--- Dangerous 777 Permissions ---"
FOUND_777=$(find "$WP_PATH" -perm 777 2>/dev/null)
if [ -z "$FOUND_777" ]; then
echo "None found. Good."
else
echo "$FOUND_777"
fi
# Check wp-config.php
echo ""
echo "--- wp-config.php Permissions ---"
if [ -f "$WP_PATH/wp-config.php" ]; then
ls -la "$WP_PATH/wp-config.php"
else
echo "wp-config.php not found in root. Checking parent..."
ls -la "$WP_PATH/../wp-config.php" 2>/dev/null || echo "Not found."
fi
# Check .htaccess
echo ""
echo "--- .htaccess Permissions ---"
if [ -f "$WP_PATH/.htaccess" ]; then
ls -la "$WP_PATH/.htaccess"
else
echo ".htaccess not found"
fi
# Sample file permissions
echo ""
echo "--- Sample File Permissions ---"
find "$WP_PATH" -maxdepth 1 -type f | head -5 | while read f; do
ls -la "$f"
done
echo ""
echo "--- Sample Directory Permissions ---"
find "$WP_PATH" -maxdepth 1 -type d | head -5 | while read d; do
ls -lad "$d"
done
echo ""
echo "Audit complete."The SetGID Bit for Shared Hosting
On shared hosting, new files created in wp-content/uploads are often owned by the web server user, not your FTP user. This creates permission conflicts when you need to manage files via FTP. The SetGID bit (chmod g+s) on a directory ensures new files and subdirectories inherit the parent directory’s group.
# Set the SetGID bit on wp-content
chmod g+s /path/to/wordpress/wp-content
# Verify the SetGID bit is set (look for 's' in group execute position)
ls -lad /path/to/wordpress/wp-content
# Output should look like: drwxr-sr-xThis is particularly useful when multiple users (FTP and web server) need to write to the same directories. The SetGID bit ensures consistent group ownership across all files and directories created inside wp-content.
How to Prevent PHP Execution in Uploads
Correct file permissions prevent unauthorized reading and writing of files, but they don’t prevent PHP execution. An attacker can still upload a .php file to wp-content/uploads and, if the permissions allow it, execute it through a direct URL request.
To block this, add this rule to your .htaccess file in wp-content/uploads:
<Files *.php>
Order Deny,Allow
Deny from all
</Files>Trusti Security includes a Directory Protection module that applies this rule automatically to wp-content/uploads and other sensitive directories with a single toggle. It detects your server type (Apache, LiteSpeed, Nginx) and writes the correct rules. For Nginx servers, it provides step-by-step manual instructions instead.
Checking for Directory Indexing
Directory indexing is another common issue. If Directory Listing is enabled, anyone can browse your wp-content/uploads directory and see every file you have ever uploaded. Trusti Security checks for this automatically in its Directory Hardening module and warns you if indexing is enabled.
To disable it manually, add this to your .htaccess:
Options -IndexesFile Ownership vs. Permissions
Permissions control what can be done. Ownership controls who can do it. On most shared hosting setups, your FTP user and the web server user (www-data, nginx, apache) are different. This means wp-content/uploads needs to be writable by the web server, but owned by your FTP user.
The ideal setup:
- All WordPress files owned by your FTP/SFTP user
- wp-content owned by the web server user (or a shared group)
- wp-content/uploads writable by the web server user
If you cannot change ownership (common on shared hosting), use 755 for directories and 644 for files, and rely on directory hardening to block PHP execution in uploads as an additional safety net.
Trusti Security for File Permission Management
Trusti Security helps with file-level protection in two ways: the Directory Protection module blocks PHP execution and directory indexing in uploads and other sensitive folders, and the File Integrity Monitor tracks changes to your WordPress core files and alerts you if anything is modified. The Admin Activity Log also tracks when theme or plugin files are edited through the WordPress admin.
File permissions are not something you set once and forget. Check them after every major WordPress update, plugin installation, or server migration. If something breaks and you are not sure why, start by checking permissions. It is usually the culprit.