Magento 2 correct file permissions
Correct file permissions for Magento 2 are: 644 for files, 755 for directories, group-write access for var, generated, pub/static, pub/media, and app/etc, and app/etc/env.php locked down to 600. The exact setup depends on whether one user or two (web server + command line) own the store and on the mode it runs in - below are ready-to-copy commands for each case.
If your permissions are broken right now, run this from the Magento root as the user who owns the files (replace <web server group> with your web server's group, usually www-data or nginx):
find . -type f -exec chmod 644 {} \;
find . -type d -exec chmod 755 {} \;
find var generated vendor pub/static pub/media app/etc -type f -exec chmod g+w {} \;
find var generated vendor pub/static pub/media app/etc -type d -exec chmod g+ws {} \;
chown -R :<web server group> .
chmod o-rwx app/etc/env.php && chmod u+x bin/magento
Single-user mode
Single-user mode is the simplest case: the same user owns the Magento files and runs the web server (typical for shared hosting). The following rules apply:
- All directories should have 755 permissions: the owner can read, write, and enter them; everyone else can only read and enter.
- All files should have 644 permissions: the owner can read and write; everyone else can only read.
- Writable directories (
var,generated,pub/media,pub/static) additionally need group-write access: g+w on files and g+ws on directories - never 777.
To set them, follow these steps:
- Log in to your server via SSH as a user with admin permissions and go to your store's root directory.
- Set permissions on the files:
bash find . -type f -exec chmod 644 {} \; - Set permissions on the directories:
bash find . -type d -exec chmod 755 {} \; - Make the writable directories group-writable:
bash find var generated pub/media pub/static -type f -exec chmod g+w {} \; find var generated pub/media pub/static -type d -exec chmod g+ws {} \;
If PHP runs as a different user than the file owner (a separate PHP-FPM pool user, for example), put both users into the same group instead of loosening permissions for everyone.
Whatever you do, never set 777 (world-writable) permissions - not on var, not on pub/media, and especially not on the app/etc directory. app/etc/env.php contains your database credentials, and public access to it is an open door for hacking your store. In single-user mode, set it to 600 (only the owner can read and write); in two-user setups, keep group access and cut off everyone else with the official chmod o-rwx app/etc/env.php:
chmod 600 app/etc/env.php
Two-user mode
This scheme works for any number of users - they just need to be split into the following groups:
- The web server group, which runs the Magento Admin (including the Setup Wizard) and the storefront;
- A command-line group, which can log in to the server remotely and perform maintenance tasks. This group should also be able to run Magento cron jobs and command-line utilities.
In this case, set the base permissions as in single-user mode, then make the shared directories writable by both groups. The current official command covers var, generated, vendor, pub/static, pub/media, and app/etc:
find var generated vendor pub/static pub/media app/etc -type f -exec chmod g+w {} \;
find var generated vendor pub/static pub/media app/etc -type d -exec chmod g+ws {} \;
chown -R :<web server group> .
You also need to let the second group execute commands and protect your store configuration:
chmod o-rwx app/etc/env.php && chmod u+x bin/magento
This will set the correct permissions for both groups.
Developer vs production mode
In developer mode, Magento constantly writes to var, generated, and pub/static, so these directories must stay writable by the web server group.
In production mode, the code should be read-only: vendor, generated, and pub/static are built during deployment, and the web server should not be able to change them at runtime. Only var and pub/media stay writable.
On production stores, we do not touch permissions by hand at all: an automated deployment script sets ownership and permissions on every release (we deploy with our own sup script; before that we used Capistrano), and direct file changes on the server are prohibited. Set permissions once in your deploy script, and they stop being a problem.
How to check and fix broken permissions
Typical symptoms of broken permissions:
- The storefront or Admin returns a 500 error after
bin/magento setup:upgrade; - Pages load without styles or images because the web server cannot write to
pub/static; - Setup complains that the command-line user "does not have read and write permissions" on the
generateddirectory.
To see the current owner, group, and permissions, run ls -l in the store root and check who owns var, generated, and pub:
ls -l
ls -l app/etc/env.php
In our support practice, whether wrong permissions are even visible depends on the web server setup - which user PHP-FPM or nginx runs as. Our quick functional check: if admin login, image uploads, and cache writes all work, the read and write permissions are sufficient; what remains is to make sure no system directories or files carry extra write permissions they should not have.
If the permissions are broken, reset them with the quick-fix block from the top of this article, run as the user who owns the files.
The most common way to break permissions today is running composer install or bin/magento commands as root: the created files become root-owned, the web server loses write access, and setup:upgrade or the readiness check fails. Always run Composer and Magento CLI commands as the file owner, never as root.
Why permissions keep drifting: umask
One-time chmod commands only fix the files that exist now - every new file created by deploys, cache writes, or image uploads gets its permissions from the process's umask, which is why permissions "drift" after you have fixed them once. Magento reads an optional magento_umask file in the store root: put 022 in it to get 755/644 on new directories and files, or leave the default 002 if you rely on the shared-group setup.
Catch permission issues before your customers do
You often need to know about issues on your store before they affect customers. To keep your maintenance staff aware of them, we offer a small extension, Issues Watcher & Notifications, that constantly monitors your store's state and notifies the responsible users about arising issues.
It can notify you by email, messenger, or phone - and it will even wake your staff in the middle of the night if something critical happens.