After migrating WordPress to another server or restoring a site from a backup, media files may stop uploading. The dashboard may display an error saying that WordPress cannot create a directory or write a file in wp-content/uploads.
The most common cause is an incorrect directory owner or missing write permission for the user running PHP-FPM. Fixing this with chmod -R 777 is not recommended: these permissions allow any process to write to the directory and increase the risk of a malicious script being placed there. A safer approach is to grant access only to the required directory and only to the required system user.
Why WordPress Cannot Upload a File
When uploading an image, WordPress does not run as your SSH user. It runs as the web process user. For PHP-FPM, this is usually www-data, nginx, or a separate site user. If the uploads directory belongs to another user and does not provide write access through the group or other permissions, PHP cannot create files there.
This problem often appears after a migration when files were copied as root, a backup administrator, or a user from the old server. At the same time, WordPress itself may continue to load normally because the existing permissions are sufficient for reading files.
- the error occurs only when uploading media;
- new thumbnails are not created after an image is uploaded;
- the PHP or Nginx log contains a Permission denied message;
- the wp-content/uploads directory belongs to root or another user.
Determine the Path and PHP User Before Changing Permissions
Run commands from the root directory of the specific site, or use the absolute path to the directory. First verify where WordPress is installed, then check the owner and current permissions of uploads.
To identify PHP-FPM processes, use:
ps aux | grep '[p]hp-fpm'
ls -ld /var/www/example.com/wp-content/uploads
find /var/www/example.com/wp-content/uploads -maxdepth 2 -printf '%M %u:%g %p\n' | head
How to Read the Output Correctly
The ps output may show master processes running as root and worker processes running as www-data or another user. The important account for file access is the worker-process user or the user specified in the PHP-FPM pool configuration.
If several sites run on the server, each pool may use its own system user. Do not automatically assign ownership to www-data in this setup. First confirm which pool serves the domain in question.
- do not rely only on the Nginx or Apache user: PHP may run under a different account;
- do not change ownership of all of /var/www if the problem affects only uploads;
- check the path before running chown to avoid changing permissions for another site.
Assign the Correct Owner to uploads
After identifying the PHP user, assign it as the owner of the uploads directory and its contents. The example uses www-data. If PHP-FPM runs as another user, replace this value with the actual account.
The chown command changes the owner and group recursively, so it fixes both the directory itself and any existing subdirectories and files.
cd /var/www/example.com
sudo chown -R www-data:www-data wp-content/uploads
When to Use a Separate Group
On a server where developers upload files through SFTP while PHP runs as a separate user, simply changing ownership can make future editing more difficult. In this setup, configure a shared group, add the required users to it, and use group permissions. This is more complex, but it is better suited to team workflows and isolated sites.
Do not give every user write access just to resolve the error quickly. Access should be granted only to the account that genuinely needs it.
Set Safe Permissions for Directories and Files
For a typical WordPress installation, 755 for directories and 644 for files is sufficient. Directories with 755 can be read and traversed, while the owner can also write to them. Files with 644 can be read, but only the owner can modify them.
Apply permissions separately to directories and files. This matters because running chmod 755 on the entire tree would make ordinary images and other files executable even though they do not need execution permissions.
cd /var/www/example.com
sudo find wp-content/uploads -type d -exec chmod 755 {} \;
sudo find wp-content/uploads -type f -exec chmod 644 {} \;
Why You Should Not Use 777
Permissions 777 allow the owner, group, and every other user to read, modify, and execute objects. For a directory, this means that any other process with access to the system can create or replace files. If an application or plugin has a vulnerability, such a directory becomes a convenient place to deploy a webshell.
Even if 777 temporarily resolves the error, it is not a correct configuration. Identify the PHP user and grant write access specifically to that account.
Check Parent Directories and Additional Restrictions
For PHP to reach uploads, it must have permission to traverse every parent directory: /var, /var/www, the site directory, and wp-content. Traversal usually requires the x permission for the relevant user or group. These directories do not need to be writable.
If the error remains after chown and chmod, the cause may not be standard Unix permissions. On systems using SELinux or similar access-control mechanisms, access may still be blocked even when the owner is correct. Also check ACLs if they are enabled on the server.
- check the permissions of every parent directory with namei -l /full/path/wp-content/uploads;
- make sure the disk is not full: df -h;
- check inodes if the server contains many small files: df -i;
- verify that the directory or filesystem is not mounted as read-only.
namei -l /var/www/example.com/wp-content/uploads
df -h
df -i
Prevent PHP File Execution in uploads
The uploads directory is intended for images, documents, and other uploads, not for executing PHP code. An additional security measure is to disable PHP file execution in this directory at the web server configuration level.
The rule depends on whether Apache or Nginx is used and on the specific server configuration. Create a configuration backup before making changes and test the syntax afterward. Do not copy random rules without understanding their effect: overly broad blocking may break legitimate file formats or site functionality.
Also check whether files with extensions such as .php, .phtml, or similar have appeared in uploads. Their presence does not always prove a compromise, but it requires checking their source and the logs.
- keep WordPress, themes, and plugins up to date;
- do not allow arbitrary file types to be uploaded unless necessary;
- check suspicious files and changes in access logs;
- do not make all of wp-content writable by the web process.
Verify the Result and Find Errors in the Logs
After changing ownership and permissions, upload a test image through the WordPress administration panel. Check whether the original file and thumbnails were created and whether the media file opens correctly on the site.
If the error occurs again, immediately review the PHP-FPM, Nginx, or Apache logs at the time of the test upload. A Permission denied message points to a file-access problem, while errors about insufficient disk space, PHP limits, or an incorrect MIME type require a different solution.
- check the owner: ls -ld wp-content/uploads;
- check the permissions of a specific file: stat wp-content/uploads/year/month/file.jpg;
- make sure PHP-FPM is using the expected pool after the changes;
- do not leave temporary 777 permissions in place after testing.
ls -ld /var/www/example.com/wp-content/uploads
stat /var/www/example.com/wp-content/uploads/2025/01/example.jpg
Frequently asked questions
Can the uploads owner be set to root?
Technically, it can, but PHP will usually not have permission to write. This does not solve the upload problem, and the temptation to add 777 creates an unsafe configuration. The owner should be the PHP-FPM user or a correctly configured group.
Is it enough to change permissions only for the uploads directory?
In most cases, yes. The web process usually needs write access to uploads, cache directories, or specific special-purpose directories. Do not grant write access to the entire WordPress installation without a specific need.
What should I do if uploads still do not work after chmod 755?
Check the owner, parent directory permissions, available disk space, inode usage, ACLs, SELinux, and the PHP-FPM and web server logs. Also confirm that the site is being served by the PHP pool whose user you configured.
Do permissions for existing files need to be changed after a migration?
Yes, if they belong to the wrong user or have excessive permissions. For a typical uploads tree, you can recursively assign the correct owner and then separately set 755 for directories and 644 for files.
Conclusion
Safely fixing uploads involves three steps: identify the PHP-FPM user, assign that user ownership of the directory, and set separate permissions for directories and files. In a typical configuration, this means chown for the web-process user, chmod 755 for directories, and chmod 644 for files.
Do not use 777 as a permanent solution or make the entire WordPress installation writable. After making the changes, test a media upload and check the logs to confirm whether file permissions were actually the cause.