chmod 777, 755, 644: What File Permissions Mean in Linux

November 6, 2026

A script refuses to run and the terminal says bash: ./deploy.sh: Permission denied. Or the opposite story: the site is down because somebody ran chmod -R 777 in the middle of the night. At the HTTP level the same thing looks like 403 Forbidden, only in the browser, while in a terminal the operating system states the refusal directly. Linux permissions look like a secret code right up to the moment you decode the three digits, and after that they are simpler than they appear.

Three groups and three actions

Every file has an owner, a group and a category for everyone else. Permissions are set separately for each group, which is why a permission string always holds three triples. There are exactly three actions as well: read, write and execute.

  • r, read: see the contents of a file or list the names inside a directory, which is bit 4;
  • w, write: change the contents of a file, or create, delete and rename files inside a directory, which is bit 2;
  • x, execute: run a file as a program, and for a directory it means being able to pass through it, which is bit 1;
  • u, user: the owner of the file; g, group: the users in the file group; o, others: everyone else, including the anonymous visitor of a website.

The reason for splitting permissions into groups is simple: on a server there is more than just you. The web server has its own group, the application has another one, the deploy user has a third. Permissions are arranged so that each part of the system does exactly what it needs and nothing more.

The octal notation: why r is 4, w is 2 and x is 1

The three actions add up as bits, and the result is one octal digit between 0 and 7. Read weighs 4, write weighs 2, execute weighs 1. One digit encodes the permissions of one group, and three digits in a row, one for the owner, one for the group and one for the others, encode the whole set.

The eight possible digits
0 = 0         ---   no permissions
1 = 1         --x   execute only
2 = 2         -w-   write only
3 = 2 + 1     -wx   write and execute
4 = 4         r--   read only
5 = 4 + 1     r-x   read and execute
6 = 4 + 2     rw-   read and write
7 = 4 + 2 + 1 rwx   all three

That table explains the three familiar numbers at once. In 644 the first digit is 6, which is 4 plus 2 for read and write, while the second and third digits are 4, read only. In 755 the first digit is 7 and the other two are 5, which is 4 plus 1 for read and execute.

What 644, 755, 777, 600 and 700 mean

  • 644, that is rw-r--r--: an ordinary file that has to be read, with only the owner allowed to modify it. The standard for text files, configs, .htaccess and the files of a website;
  • 755, that is rwxr-xr-x: a file that has to be executed, or a directory that has to be entered. The owner reads, writes and executes, the group and the others read and execute but do not write;
  • 777, that is rwxrwxrwx: every permission for everyone, which on a live server is almost always a mistake;
  • 600, that is rw-------: a file only its owner can reach. That is how passwords, keys and .env files are handled;
  • 700, that is rwx------: a directory or script reachable by the owner alone. A personal home directory and ~/.ssh look exactly like this;
  • 750, that is rwxr-x---: a directory the group can enter, a common setup for an application folder.

777 deserves a word of its own, because it is the value most often recommended on the internet. Write permission for the others category means that absolutely any user on the server, including a compromised site in a neighbouring account, can create and modify a file. If that file is executable or is loaded by the web server, someone can drop their own code in it and it will run with the privileges of the server. For an uploads folder full of images it is a path to a malicious upload, for a config holding a database password it is a path to a leak.

The symbolic form rwxr-xr-x

Octal numbers are convenient in scripts, but nobody has to memorise what 755 means. The symbolic form reads directly: ten characters, three groups of three positions, in the order owner, group, others. A dash means the permission is missing.

There is a third form in which every permission is written as its own operation. It is handy because it changes exactly what you want and leaves the rest alone: u+x adds execute for the owner, g-w removes write for the group, o=r leaves the others with read only. The order of the operations in the command does not matter, while the order of the letters in the symbolic form absolutely does.

One set of permissions in three notations
Number:     755
Symbolic:   rwxr-xr-x
Exploded:   chmod u+r,u+w,u+x,g+r,g+x,o+r,o+x
For a file: chmod 755 filename
For a directory: chmod 755 directory/

A directory needs x, and here is why

For a file the permissions read the way you expect: r opens the contents, w changes them, x runs it. For a directory the meaning is different, and this is where beginners go wrong, because instinct says more is always better.

  • r on a directory is the right to see the list of file names;
  • w on a directory is the right to create files in it, delete them and rename them;
  • x on a directory is the right to pass through it: to change into it and to open the files inside;
  • r and w without x give a strange result: the names are visible but entering is impossible;
  • x without r gives the opposite: you can get in but you cannot list the contents.

The practical rule follows: a directory without x is broken whatever else it says. The other way round is true too. If a directory is locked down to 700 and the file inside is set to 644, the owner still cannot read the file, because entering the directory is not allowed. The permissions of a file never work around the permissions of the directory holding it.

umask: where 644 and 755 come from

The permissions of a new file are not invented at creation time, they are derived from a mask called umask. The mask lists the permissions that are forbidden. A file is created as 666, a directory as 777, and the mask is subtracted from those base values.

The default mask on most Linux distributions is 022. That means write for the group and for the others is forbidden on a new file, which leaves 644, and write for the others is forbidden on a new directory, which leaves 755. That is why everything on a fresh server looks uniform, and it is also why "the permissions got lost" usually means that somebody changed the mask or copied files in from somewhere with different settings.

How the mask turns base permissions into final ones
Base permissions: file 666, directory 777

umask 022 (the default) → files 644, directories 755
umask 002              → files 664, directories 775
umask 027              → files 640, directories 750
umask 077              → files 600, directories 700
umask 000              → files 666, directories 777

The umask command shows the current mask and umask 027 in the same shell changes it, after which new files are created with tighter permissions. One detail people forget: the mask only affects new objects, the permissions of files and directories that already exist stay exactly as they are.

How it looks in ls -l

The command ls -l puts ten characters at the start of every line. The first one describes the type of the object, the other nine are the permissions in symbolic form, and after that come the link count, the owner, the group, the size, the date and the name.

Output of ls -l
-rw-r--r--  1 www-data www-data   1234 Nov  3 10:12 index.php
drwxr-xr-x  2 www-data www-data   4096 Nov  3 10:12 uploads
-rwxr-xr-x  1 deploy    deploy     512 Nov  3 09:40 backup.sh
-rw-------  1 deploy    deploy       96 Nov  3 09:38 .env
lrwxrwxrwx  1 www-data www-data      12 Nov  3 10:12 current -> releases

The first character decodes like this: a dash for an ordinary file, d for a directory, l for a symbolic link, c for a character device and b for a block device. Then come the three groups of three, and the answer can be read straight off them: index.php is 644, uploads is 755, backup.sh is 755 and .env is 600. A symbolic link shows 777, but those bits mean nothing, because access is decided by the permissions of the target the link points at.

Picking permissions without guessing

Open the chmod calculator: it shows four views of one set of permissions at once, the octal number, the symbolic form, the list of individual flags and a ready to paste command. There are presets for 644, 755, 777, 700, 600, 750, 666 and 400, a switch between file and directory, and a field where you can type a number and get the decoding back. For instance 755 turns into rwxr-xr-x and into the command chmod 755 filename, while a directory gets chmod 755 directory/.

Scheduling is the neighbouring task. If a script is launched from cron it needs the execute bit, and the log or lock file is better kept closed: 644 for a log, 600 for anything sensitive. A cron expression parser helps with the schedule itself, and the same calculator covers the permissions of the script. How the five fields of an expression turn into a schedule in plain words is explained in the article about cron in simple terms.

Typical mistakes

  • chmod -R 777 across the whole site: the problem is not that it stops working, it is that it works far too widely;
  • a missing x on a directory: 666 on a directory looks harmless and still refuses to let anyone in;
  • trying to make a directory executable so that a script inside it can run: the execute bit belongs on the file, while the directory needs x for traversal;
  • changing the permissions of a directory instead of the file: the script will not start because the .sh file itself lacks x;
  • permissions on .htaccess: 777 lets any visitor append their own directives, the right value there is 644;
  • chmod 600 on a public folder: uploaded files stop being served if the web server runs as a different user;
  • chmod 755 on a data file: for a config, a password or a key, execute is pointless, 644 or 600 is enough.

Common questions

Why did my script stop running after a site migration?

More often than not the permissions are not the problem at all: the execute bit was lost during the copy, or the owner changed along with it. Look at the ls -l output for the file in question and compare it with what you expected. A symbolic link created before the migration may point nowhere, and then the problem looks like a permissions issue while it is really a broken link.

What is the difference between 644 and 664?

The second digit. In 664 the group moves to 6, which is 4 plus 2 for read and write, while the others stay at 4 with read only. For a single file in a working folder the difference hardly matters, but on a shared directory 664 lets a colleague in the same group modify the contents. The comparison with 775 works the same way: the second position of the directory goes from 5 to 7, so the group gains write.

What are setuid, setgid and the sticky bit?

They are extra bits written as a fourth digit in front of the main three. Setuid makes a program run with the permissions of the file owner, setgid makes new files inherit the group of the directory, and the sticky bit, shown as t, stops anyone but the owner of the file, the owner of the directory and the superuser from deleting files in that directory. The classic example is /tmp, which looks like drwxrwxrwt.

How is chmod different from chown?

A file has three independent attributes and mixing them up is common. chmod changes the permissions, chown changes the owner and chgrp changes the group. If a script refuses to run because the execute bit is missing, chmod is the answer; if the owner does not match, chown is. On a server with several users the owner and the group are usually set once, while permissions are tuned in small doses.

Do cron scripts need 755?

Yes, when the job runs the file directly. The classic setup gives the script 755, the log or lock file 644, and anything sensitive 600. One more thing worth knowing about cron is that its PATH is minimal, so it is safer to spell out absolute paths to the interpreter and to the script itself.

The rule of thumb is short: 644 for ordinary files, 755 for directories and executable files, 600 for anything holding a secret. Anything outside those three values is a deliberate decision, and it is worth writing down next to the command why that particular value was chosen.

Related articles