How to fix “The uploaded file could not be moved to wp-content/uploads/” in WordPress
If you use WordPress, you may have encountered this problem: you try to upload a new file and it throws this error message at you. This is also why you could not click the button in the dashboard to upgrade theme, plugin or WordPress versions.
In this article, let’s go through the problem’s cause and solution once and for all.
Why does it happen?
TL;DR: Your web server’s file ownership isn’t set up correctly. The web server process that takes browser requests does not have file ownership to your WordPress directory.
The wrong way to fix it
A common suggestion that you’ll find online regarding this problem is to change everything under your WordPress upload folder (for example
wp-contents/uploads) to file permission mode
chmod. This means anyone can read, write and execute files under that folder.
This is a horrible idea. Yes, this may temporarily mitigate the problem, but it does so by creating a huge security concern in your server. It’s never a good idea to give more than necessary permissions to anyone, especially the execute file permission, which opens up malicious injection possibilities that may cause server downtime or data loss.
The right way to fix it
The right way to fix this problem is to assign proper file ownership to the correct server processes.
Let’s start by log into your server. Identify the server software that powers your WordPress – this may be Apache (a common choice), or in my case, NGINX. We would like to search for any process instances running under the Unix’s process status (`ps`) panel:
root@li1007-15:~# ps aux | grep nginx root 6246 0.0 0.0 76312 132 ? Ss Mar18 0:00 nginx: master process /usr/bin/openresty -g daemon off; www-data 6312 0.0 0.1 78416 1412 ? S Mar18 4:14 nginx: worker process root 13920 0.0 0.0 76312 364 ? Ss Mar19 0:00 nginx: master process /usr/bin/openresty -g daemon off; www-data 13985 0.0 0.1 78436 1508 ? S Mar19 9:30 nginx: worker process systemd+ 13997 0.0 0.1 34084 1548 ? S Mar19 16:55 nginx: worker process root 22093 0.0 0.0 14428 936 pts/0 S+ 16:38 0:00 grep --color=auto nginx root 23776 0.0 0.0 17956 8 ? Ss Mar17 0:00 /bin/bash -c source ".profile" 2>/dev/null; docker-gen -watch -notify "nginx -s reload" /app/nginx.tmpl /etc/nginx/conf.d/default.conf root 23777 0.0 0.0 17948 0 ? Ss Mar17 0:00 /bin/bash -c source ".profile" 2>/dev/null; nginx root 23778 0.1 0.1 14552 1708 ? Sl Mar17 117:33 docker-gen -watch -notify nginx -s reload /app/nginx.tmpl /etc/nginx/conf.d/default.conf root 23780 0.0 0.0 33596 216 ? S Mar17 0:00 nginx: master process nginx root 31964 0.0 0.0 76312 156 ? Ss Mar18 0:00 nginx: master process /usr/bin/openresty -g daemon off; www-data 32029 0.0 0.1 78436 1364 ? S Mar18 1:46 nginx: worker process root 32584 0.0 0.0 76312 32 ? Ss Mar17 0:00 nginx: master process /usr/bin/openresty -g daemon off; www-data 32650 0.0 0.0 78460 824 ? S Mar17 0:16 nginx: worker process
The first column is the user owning that specific process. The first row indicates that the NGINX master process is owned by the
root user. This is good, because in my case,
root user is already the owner of the WordPress directory.
The web server’s master process is also responsible for spawning many worker (child) processes for load balancing. The culprit is that these web server worker processes that actually handle requests from the browser belong to a different user than
root: in my case,
www-data, which does not have access to your WordPress directory.
Let’s change the ownership of your WordPress directory to the worker process user:
chown -R www-data /path/to/your/wordpress/directory
There is no need to restart the server since the alterations are applied to the file system only. Simply reload the WordPress dashboard in your browser and try uploading files again. This problem should be resolved.