file-permissions php upload

move_uploaded_file gives “failed to open stream: Permission denied” error


I keep getting this error when trying to configure the upload directory with Apache 2.2 and PHP 5.3 on CentOS.

In php.ini:

upload_tmp_dir = /var/www/html/mysite/tmp_file_upload/

In httpd.conf:

Directory /var/www/html/mysite/tmp_file_upload/>
    Options  -Indexes
    AllowOverride None
    Order allow,deny
    Allow from all
<Directory /var/www/html/mysite/images/>
                Options -Indexes

CentOS directory permissions:

drwxrwxr-x 2 root root 4096 Nov 11 10:01 images
drwxr-xr-x 2 root root 4096 Nov 12 04:54 tmp_file_upload

No matter what I do, I keep getting this error from PHP when I upload the file:

Warning: move_uploaded_file(images/robot.jpg): failed to open stream: Permission denied in /var/www/html/mysite/process.php on line 78

Warning: move_uploaded_file(): Unable to move ‘/tmp/phpsKD2Qm’ to ‘images/robot.jpg’ in /var/www/html/mysite/process.php on line 78

As you can see, it never did take the configuration from the php.ini file regarding the upload file.

What am I doing wrong here?


  • 775? Maybe your server is running as nobody. Only root can write in this case (your “images” permissions)…

    Nov 12, 2011 at 10:34

  • 1

    what does it means ? how can i change it ?

    – user63898

    Nov 12, 2011 at 11:16

  • Remember that ALL parent directories also need to have the right permissions.

    Sep 19, 2017 at 17:56

  • just a footnote here from my recent wall banging episode.. remember that sometimes linux can too be fickle. I tried all manner of things and eventually renamed the dest directory and re-created it and it worked just fine. permissions, ownership etc. identical to the old one..

    – l0ft13

    Aug 10 at 13:40


This is because images and tmp_file_upload are only writable by root user. For upload to work we need to make the owner of those folders same as httpd process owner OR make them globally writable (bad practice).

  1. Check apache process owner: $ps aux | grep httpd. The first column will be the owner typically it will be nobody
  2. Change the owner of images and tmp_file_upload to be become nobody or whatever the owner you found in step 1.

    $sudo chown nobody /var/www/html/mysite/images/
    $sudo chown nobody /var/www/html/mysite/tmp_file_upload/
  3. Chmod images and tmp_file_upload now to be writable by the owner, if needed [Seems you already have this in place]. Mentioned in @Dmitry Teplyakov answer.

    $ sudo chmod -R 0755 /var/www/html/mysite/images/
    $ sudo chmod -R 0755 /var/www/html/mysite/tmp_file_upload/
  4. For more details why this behavior happend, check the manual , note that it also talking about open_basedir directive.


  • 4

    Thanks: our old owner had been daemon it is now apache

    – zzapper

    Jun 18, 2013 at 14:48

  • This fix applies to situations where you might of changed the servers php type from fast_CGI, CGI to Apache_mod as plesk etc.. can continue with original user’s permissions not apache. This fixed my issues.

    Oct 16, 2014 at 4:31

  • 1

    I am having this same error but both the process and folders are owned by jacob (me as it is my local machine) and the folders all have 755 or 775.

    Feb 8, 2015 at 19:00

  • 1

    I had to restart my apache process sudo service httpd restart after changing permissions. Then it worked 🙂 Instead of changing owner chown I added my apache process to a ‘www’ group and added these directories to the same ‘www’ group through chgrp

    – Ali Saeed

    Apr 9, 2015 at 15:27


You can also run this script to find out the Apache process owner:

<?php echo exec('whoami'); ?>

And then change the owner of the destination directory to what you’ve got. Use the command:

chown user destination_dir

And then use the command

chmod 755 destination_dir

to change the destination directory permission.


  • 4

    Thanks it works for me. I first used Laith Shadeed’s method but I don’t get same result when typing ps aux | grep httpd and <?php echo exec('whoami'); ?>. Does anyone know why ?

    – kukinsula

    Jun 17, 2014 at 16:17

  • 2

    ps aux | grep https doesn’t return web server owner name. This does : ps aux | grep -E ‘[a]pache|[h]ttpd|[_]www|[w]ww-data|[n]ginx’ | grep -v root | head -1 | cut -d\ -f1 Fron Symfony doc.

    Jul 22, 2014 at 10:54

  • 1

    Note that in the above command, there should be two spaces between “-d\” and “-f1”. If you copy-paste as-is, you may get an error like “cut: bad delimiter”.

    – Beejor

    Apr 5, 2015 at 0:07

  • 2

    plus 1 for exec('whoami'). Saved me 30 more minutes. was chowning ubuntu user

    Apr 14, 2015 at 17:45

  • 17

    should this be www-data? usually

    – maxisme

    Apr 27, 2015 at 15:45


This worked for me.

sudo adduser <username> www-data
sudo chown -R www-data:www-data /var/www
sudo chmod -R g+rwX /var/www

Then logout or reboot.

If SELinux complains, try the following

sudo semanage fcontext -a -t httpd_sys_rw_content_t '/var/www(/.*)?'
sudo restorecon -Rv '/var/www(/.*)?'


  • saved my life :).. i use GIT post-recive hook to deploy my web, and every time i deploy i get his permission denied error, adding git user to www-data fixed it 🙂 thank you

    – Zalaboza

    Aug 8, 2017 at 7:49

  • This is the best answer.

    Nov 8, 2017 at 16:19

  • Don’t worry! your answer is the best in our hearts. You just saved my life and I do not know how to say thank you!!!!

    Jul 16, 2021 at 14:09