Chmod Calculator
Visual Unix and Linux file permission calculator. Toggle permissions, enter numeric values, or type symbolic notation directly.
Definition
chmod (change mode) is a Unix/Linux command used to set file and directory access permissions. Permissions are expressed as a three-digit octal number where each digit represents permissions for owner, group, and others. Each digit is a sum of read (4), write (2), and execute (1). For example, 755 grants full access to the owner and read/execute to everyone else.
Special Permission Bits
Common Permission Presets
Useful chmod Commands
| Number | Permission | Symbolic | Binary |
|---|---|---|---|
| 0 | No permission | --- | 000 |
| 1 | Execute | --x | 001 |
| 2 | Write | -w- | 010 |
| 3 | Write + Execute | -wx | 011 |
| 4 | Read | r-- | 100 |
| 5 | Read + Execute | r-x | 101 |
| 6 | Read + Write | rw- | 110 |
| 7 | Read + Write + Execute | rwx | 111 |
Understanding Unix File Permissions
Unix and Linux file permissions are a basic security mechanism that controls who can access files and directories and what they can do with them. Every file and directory on a Unix-based system has an associated set of permissions that determine three types of access: read, write, and execute. These permissions are assigned to three categories of users: the file owner (user), the file's group, and everyone else (others).
I work with chmod permissions daily when deploying web applications, configuring server environments, managing SSH keys, and setting up automated scripts. Understanding the permission system thoroughly is important for anyone who administers Unix or Linux servers, develops backend applications, or works with containerized deployments.
The Permission Model
Each file has nine permission bits arranged in three groups of three. The first group applies to the owner (the user who created the file). The second group applies to the group (a set of users defined by the system administrator). The third group applies to others (everyone else on the system). Within each group, the three bits represent read (r), write (w), and execute (x).
For regular files, read permission allows viewing the file's contents, write permission allows modifying the file, and execute permission allows running the file as a program or script. For directories, the permissions have slightly different meanings. Read permission on a directory allows listing the directory's contents. Write permission allows creating, deleting, and renaming files within the directory. Execute permission allows entering the directory (using cd) and accessing files within it by name.
A critical detail that many beginners miss is that directory execute permission is required to access any file inside the directory, even if the file itself has read permission. If a directory has permissions 700 (rwx------), only the owner can access files inside it, regardless of the individual file permissions.
Numeric (Octal) Notation
The numeric notation represents each permission group as a single octal digit from 0 to 7. The digit is calculated by adding the values of the active permissions: read equals 4, write equals 2, and execute equals 1. So 7 means all permissions (4+2+1), 6 means read and write (4+2), 5 means read and execute (4+1), and 4 means read only.
The full numeric notation consists of three digits representing owner, group, and others, in that order. For example, 644 means the owner has read and write (6 = 4+2), the group has read only (4), and others have read only (4). This is the standard permission for most regular files on a Unix system.
An optional fourth digit at the beginning represents special permission bits: setuid (4), setgid (2), and sticky bit (1). So 4755 means setuid is active, and the file has standard 755 permissions. When the fourth digit is zero, it is usually omitted, so 0755 is written as simply 755.
Symbolic Notation
Symbolic notation uses letters and operators to represent permissions. The notation consists of a who component (u for user/owner, g for group, o for others, a for all), an operator (+ to add, - to remove, = to set exactly), and a permission component (r, w, x, or combinations). Multiple operations can be separated by commas.
For example, chmod u+x file.sh adds execute permission for the owner without changing any other permissions. chmod go-w file.txt removes write permission from group and others. chmod a="r" file.txt sets read-only for everyone, removing any existing write or execute permissions. chmod u="rwx,g=rx,o=rx" dir/ sets the exact permissions 755.
The advantage of symbolic notation is that it modifies specific permissions without affecting others. With numeric notation, you must specify all permissions at once. If a file has permissions 755 and you want to add write for the group, you need to know the current permissions and calculate the new value (775). With symbolic notation, you simply write chmod g+w file regardless of the existing permissions.
Common Permission Settings
Different types of files and directories require different permission settings for proper security. Regular files that contain data (text files, images, configurations) should typically have 644 (rw-r--r--), allowing the owner to read and write while others can only read. This is the default permission set by most applications when creating files.
Executable files and scripts need the execute bit set. The standard setting is 755 (rwxr-xr-x), which allows anyone to run the program but only the owner to modify it. Shell scripts, Python scripts, and compiled binaries all need execute permission to run directly.
Directories should typically have 755 (rwxr-xr-x) for publicly accessible locations and 700 (rwx------) for private directories. Web server document roots are usually 755 so the web server process can read and traverse them. User home directories are often 700 or 750 depending on the system's privacy policy.
Private files like SSH keys require strict permissions. The ~/.ssh directory should be 700, private keys should be 600 (rw-------), and the authorized_keys file should be 600 or 644. The SSH client and server enforce these restrictions and will refuse to use keys with overly permissive settings.
Special Permission Bits
Beyond the standard nine permission bits, Unix supports three special bits that modify how files and directories behave. The setuid bit (value 4 in the special digit, or chmod u+s) on an executable file causes the program to run with the file owner's privileges instead of the executing user's privileges. The classic example is the /usr/bin/passwd command, which is owned by root and has setuid set. When a regular user runs passwd to change their password, the program runs as root so it can modify the /etc/shadow file.
The setgid bit (value 2, or chmod g+s) behaves differently for files and directories. On an executable file, it works like setuid but with the file's group instead of the owner. On a directory, setgid causes new files created inside the directory to inherit the directory's group rather than the creating user's primary group. This is commonly used for shared project directories where all team members need files to belong to the same group.
The sticky bit (value 1, or chmod +t) on a directory restricts file deletion. In a directory with the sticky bit set, only the file owner, the directory owner, or root can delete files. The most common example is /tmp, which typically has permissions 1777. All users can create files in /tmp, but no user can delete another user's files.
Default Permissions and umask
When a new file or directory is created, the operating system applies default permissions that are modified by the umask (user file-creation mask). The base permissions for new files are 666 (rw-rw-rw-) and for new directories are 777 (rwxrwxrwx). The umask is subtracted from these base permissions to determine the actual permissions.
A common umask value is 022, which removes write permission for group and others. With umask 022, new files get 644 (666 - 022) and new directories get 755 (777 - 022). A more restrictive umask of 077 removes all permissions for group and others, resulting in 600 for files and 700 for directories.
You can check your current umask by running the umask command. To change it temporarily for the current session, run umask 022 (or whatever value you prefer). To set it permanently, add the umask command to your shell configuration file (~/.bashrc, ~/.zshrc, or /etc/profile for system-wide settings).
File Ownership
Permissions work in conjunction with file ownership. Every file has an owner (a user) and a group. The chown (change owner) command modifies file ownership. The syntax is chown user:group file. For example, chown www-data:www-data /var/www/html/ sets both the owner and group to the web server user, which is a common configuration for web application files.
The chgrp (change group) command changes only the group ownership. This is useful when multiple users need shared access to files through a common group. Create a group for the project team, add all team members to the group, set the project directory's group to the team group, and apply setgid so new files inherit the group automatically.
Permissions in Web Server Configurations
Web servers like Apache and Nginx run as a specific system user (commonly www-data, apache, or nginx). Files served by the web server must be readable by this user. If the web server user is not the file owner and not in the file's group, it accesses files through the "others" permissions.
For a typical web application deployment, I set the application directory to 755 with ownership by the deployment user and group www-data. PHP, Python, or Node.js files get 644. Upload directories where the web server needs to write files get 775 with group ownership by the web server user. Configuration files containing database passwords or API keys get 640 with group www-data, readable by the web server but not by other users.
A common security mistake is setting everything to 777 to "fix" permission errors. This gives every user on the system full access to the files, including the ability to modify or delete them. Instead of using 777, diagnose which specific user needs which specific permission and set it precisely. Running ls -la shows current permissions and ownership, and namei -l /path/to/file shows permissions for every directory in the path.
Permissions in Docker and Containers
Container environments add a layer of complexity to file permissions. When you mount a host directory into a Docker container, the files retain their host permissions, but the user IDs inside the container may not match the host user IDs. A file owned by UID 1000 on the host is owned by whatever user has UID 1000 inside the container, which might be a different user or might not exist at all.
To handle this, set the container's working user to match the host user's UID using the --user flag or the USER directive in the Dockerfile. Alternatively, use a named volume instead of a bind mount, which allows the container to manage its own permissions. For shared development environments, consider using the :z or :Z suffixes on SELinux systems to handle permission relabeling automatically.
Access Control Lists (ACLs)
Standard Unix permissions are limited to three groups (owner, group, others). For more granular control, modern Unix systems support Access Control Lists (ACLs). ACLs allow you to set specific permissions for individual users and groups beyond the standard owner/group model.
The setfacl command sets ACL entries. For example, setfacl -m u:alice:rw file.txt grants user alice read and write access to file.txt, regardless of the standard permission bits. The getfacl command displays the current ACL. Files with ACLs show a + sign after the permission string in ls -l output (e.g., -rw-r--r--+).
ACLs are useful in shared hosting environments, team project directories, and any scenario where the standard owner/group model is insufficient. However, they add complexity and can be confusing to debug. I recommend using standard permissions whenever possible and reserving ACLs for cases where multiple specific users need different access levels to the same files.
Permissions in Version Control
Git tracks the execute bit for files but does not track full Unix permissions or ownership. When you commit a file with execute permission set, Git records it as mode 100755. Files without execute permission are recorded as 100644. Other permission combinations (like 600 or 444) are normalized to one of these two modes.
This means that when you clone a repository, files either come out as 755 (executable) or 644 (non-executable), modified by your umask. If your deployment requires specific permissions (like 600 for private keys), you need to set them as a post-checkout or deployment step, not by relying on Git to preserve them.
The git config core.fileMode setting controls whether Git pays attention to file permission changes. When set to true (the default on Linux), changing a file's permission without changing its content creates a diff. When set to false (the default on Windows and macOS FAT drives), permission changes are ignored. Set this to false on shared repositories where different developers use different operating systems.
Security Implications of Incorrect Permissions
Misconfigured file permissions are one of the most common server security vulnerabilities. World-writable files (o+w, like 666 or 777) allow any user on the system to modify them. If an attacker gains access as any user (even an unprivileged service account), they can modify configuration files, inject malicious code into web applications, or replace binaries with trojaned versions.
World-readable sensitive files expose credentials and private keys. Database configuration files, API key files, TLS private keys, and SSH private keys should never be world-readable. Set these to 600 (owner read/write only) or 640 (owner read/write, group read) if a service running as a different user needs to read them through group membership.
Regular security audits should check for permission anomalies. The command find / -perm -o+w -type f 2>/dev/null lists all world-writable files on the system. Similarly, find / -perm -4000 -type f lists all setuid executables. Any unexpected entries in these lists should be investigated as potential security issues.
Permissions in CI/CD Pipelines
Continuous integration and deployment pipelines often encounter permission issues when building, testing, and deploying applications. Build artifacts created inside Docker containers may have root ownership. Files transferred between pipeline stages may lose their execute permissions. SSH keys used for deployment must have exactly 600 permissions or SSH will refuse to use them.
In GitHub Actions, GitLab CI, and Jenkins pipelines, I include explicit chmod commands after checking out code, extracting archives, or copying files between stages. A common pattern in deployment scripts is to set permissions immediately after extracting the application files: find /app -type d -exec chmod 755 {} \; for directories and find /app -type f -exec chmod 644 {} \; for files, followed by chmod +x /app/bin/* for executables. This ensures consistent permissions regardless of how the files were packaged or transferred.
For secrets management in pipelines, write credential files with restrictive permissions using commands like install -m 600 /dev/null ~/.ssh/deploy_key before writing the key content. The install command creates the file with the specified permissions atomically, avoiding the brief window where a file exists with default permissions before chmod is applied.
macOS and BSD Permission Differences
While macOS is built on BSD Unix and uses the same basic permission model, there are notable differences. macOS adds an extended security framework with System Integrity Protection (SIP) that prevents modifications to system files regardless of permissions. Even root cannot modify files protected by SIP. Also, macOS uses extended attributes and file flags that can restrict access beyond what standard permissions allow.
The ls -l@ command on macOS shows extended attributes, and the ls -lO command shows file flags. The uchg (user immutable) flag prevents the file from being modified, renamed, or deleted. The schg (system immutable) flag provides even stronger protection that can only be removed in single-user mode. These flags work alongside standard Unix permissions to provide defense-in-depth security.
BSD-based systems (FreeBSD, OpenBSD, NetBSD, and macOS) also support the chflags command for setting file flags. The append-only flag (sappnd) allows data to be added to a file but not modified or deleted, which is useful for log files that should be tamper-resistant. The no-unlink flag (sunlnk) prevents file deletion even by the owner.
Permissions for Common Application Types
Different application types have established permission conventions. For PHP web applications (WordPress, Laravel, Drupal), the recommended structure is: application files at 644, directories at 755, configuration files with database credentials at 640 or 600, and upload/cache directories at 775 with group ownership matching the web server user. WordPress specifically recommends wp-config.php at 440 or 400 for maximum security.
For Node.js applications, the pattern is similar: source files at 644, directories at 755, node_modules at standard permissions (created by npm), the .env file at 600, and any executable scripts in the bin directory at 755. The application should run as a non-root user with a dedicated service account.
For Python applications, virtual environment directories need 755 with executables in the bin directory set to 755. The application source gets 644 for modules and 755 for scripts intended to be run directly. WSGI configuration files (gunicorn.conf.py, uwsgi.ini) get 644 or 640 depending on whether they contain sensitive values.
Database file permissions vary by database system. SQLite database files should be 660 with ownership matching the application user and group. PostgreSQL data directories are typically 700 with ownership by the postgres system user. MySQL/MariaDB data directories use 750 by default. These permissions are set automatically during installation, and changing them can cause the database service to fail to start.
Troubleshooting Permission Errors
Permission denied errors are among the most common issues on Unix systems. When you encounter "Permission denied," start by checking the file permissions with ls -la and the file ownership. If the permissions look correct, check every directory in the path. Remember that execute permission on every parent directory is required to access a file.
Use the id command to see your current user ID, group memberships, and effective groups. A common mistake is assuming that adding a user to a group takes effect immediately. On most systems, group membership changes require the user to log out and log back in (or start a new shell with newgrp groupname) for the new group to appear in the effective group list.
The stat command provides detailed file information including numeric permissions, owner, group, and timestamps. For debugging path-related permission issues, namei -l /full/path/to/file lists the permissions for every component of the path, making it easy to identify which directory is blocking access.
On SELinux-enabled systems (Red Hat, CentOS, Fedora), standard Unix permissions might look correct but access is still denied due to SELinux security contexts. The ls -Z command shows SELinux contexts, and ausearch -m AVC -ts recent shows recent SELinux denials. Use restorecon -R /path to reset contexts to their expected values for the file's location.
Permissions and Filesystem Types
Not all filesystems support Unix permissions equally. Native Linux filesystems (ext4, XFS, Btrfs, ZFS) fully support permissions, ownership, ACLs, and extended attributes. FAT32 and exFAT filesystems (commonly used on USB drives and SD cards) do not support Unix permissions at all. When mounting FAT volumes, Linux uses mount options (fmask, dmask, uid, gid) to assign artificial permissions to all files and directories on the volume.
NTFS (the Windows filesystem) has its own ACL-based permission system. When mounting NTFS on Linux using ntfs-3g, the driver maps NTFS permissions to Unix permissions. The mapping is imperfect, and files may appear with unexpected permissions. For consistent behavior, specify uid, gid, fmask, and dmask in the mount options.
Network filesystems like NFS and CIFS/SMB have their own permission handling. NFS typically maps UIDs directly between client and server, which requires consistent UID numbering across machines. NFSv4 supports ACLs that translate between the client and server. CIFS mounts from Windows servers use mount options to set Unix permissions since the underlying Windows ACLs do not translate directly.
Automating Permission Management
For production servers, I manage file permissions through configuration management tools rather than manual chmod commands. Ansible, Chef, Puppet, and Salt all support setting file permissions, ownership, and ACLs as part of their declarative configuration. This ensures permissions are consistent across all servers and are automatically corrected if someone changes them manually.
In Ansible, the file module sets permissions declaratively: file: path="/var/www" state="directory" mode="0755" owner="www-data" group="www-data" recurse="yes. In a Dockerfile, the COPY --chmod="644 directive (available since BuildKit) sets permissions during the image build without needing a separate RUN chmod command.
Monitoring tools can alert on permission changes. Tools like AIDE, Tripwire, and OSSEC maintain a database of expected file permissions and report deviations. Integrating these tools into your security monitoring infrastructure provides early warning if permissions are changed by an unauthorized process or compromised account, which could indicate a security breach or configuration drift.
Permission Inheritance and Propagation
Unlike Windows NTFS, Unix permissions are not inherited from parent directories. When you create a file, its permissions are determined by the creating process's umask, not by the parent directory's permissions. This means that setting a directory to 755 does not cause files created inside it to also be 755. The setgid bit on directories is the one exception: it causes new files to inherit the directory's group ownership (but not its permissions).
To propagate permissions to existing files within a directory tree, use the find command with -exec chmod. The pattern find /path -type f -exec chmod 644 {} + sets all files to 644, while find /path -type d -exec chmod 755 {} + sets all directories to 755. Using + instead of \; is significantly faster because it batches multiple files into a single chmod invocation.
The chmod -R (recursive) flag applies the same permission to all files and directories in a tree. This is problematic because files and directories usually need different permissions (files should not have execute permission, directories must have it). Always use separate find commands for files and directories instead of chmod -R with a single permission value.
Understanding the ls -l Output
The ls -l command displays file permissions in the first column as a 10-character string. The first character indicates the file type: - for regular files, d for directories, l for symbolic links, c for character devices, b for block devices, p for named pipes, and s for sockets. The remaining nine characters show the permissions for owner, group, and others in three groups of three.
Special permission bits modify the display. When setuid is active, the owner's execute position shows s (if execute is also set) or S (if execute is not set). When setgid is active, the group's execute position shows s or S. When the sticky bit is active, the others' execute position shows t (if execute is also set) or T (if execute is not set). An uppercase letter indicates the special bit is set but the underlying execute permission is not, which is unusual and may indicate a configuration error.
After the permission string, ls -l shows the link count, owner name, group name, file size, modification date, and filename. The link count for directories indicates the number of subdirectories plus 2 (for the . and .. entries). For regular files, the link count shows the number of hard links pointing to the file's data on disk.
Permissions and System Calls
At the kernel level, permission checks happen during system calls. The open() system call checks read and write permissions based on the flags passed (O_RDONLY, O_WRONLY, O_RDWR). The execve() system call checks execute permission. The access() system call allows a process to check permissions without actually opening the file, which is useful for determining what operations are available before attempting them.
The kernel checks permissions in a specific order. If the process's effective user ID matches the file's owner, the owner permissions apply. If the process's effective group ID (or any supplementary group) matches the file's group, the group permissions apply. Otherwise, the others permissions apply. Note that only one category applies; they do not accumulate. A file owner who has read permission through the owner category but not through the group category can read the file, even if the owner is also a member of the file's group.
The root user (UID 0) bypasses most permission checks. Root can read and write any file regardless of permissions. Execute permission is the one exception: root can only execute a file if at least one of the three execute bits is set. This prevents root from accidentally running data files as programs. However, root can always change permissions with chmod, effectively gaining the ability to execute any file by first adding the execute bit.
Practical Permission Recipes
Here are permission configurations I use regularly in production environments. For a web application deployment with Nginx serving static files and proxying to a backend application: the document root is 755 owned by the deployment user with group www-data, static assets (CSS, JS, images) are 644, uploaded files are 644 in a directory that is 775 with setgid set so uploads inherit the correct group, and the application configuration file is 640 readable by the backend process through group membership.
For a shared development server where multiple developers collaborate on projects: the project directory is 2775 (setgid + rwxrwxr-x) owned by root with the dev team's group. All developers are members of this group. The setgid bit ensures new files inherit the group, and the 775 permission allows all group members to create and modify files. Individual developers' private files can be set to 600 within their own subdirectories.
For a backup server receiving rsync transfers from multiple sources: the backup directory for each source is 700 owned by the backup service user, preventing any source from reading another source's backups. Backup scripts are 700 to prevent tampering. Backup logs are 640 with group membership granted to the monitoring system. The backup rotation script is 700 and owned by root to prevent backup deletion by compromised service accounts.
For a database server, the data directory permissions are critical. PostgreSQL requires its data directory to be 700 and owned by the postgres user. The server will refuse to start if these permissions are wrong. MySQL and MariaDB use 750 for the data directory. Socket files created by database servers typically need 755 on the containing directory so client applications can connect through the Unix socket. Always verify data directory permissions after system upgrades, as package managers occasionally reset them to defaults.
Frequently Asked Questions
Video Guide
Community Questions
What does chmod 777 mean and when should I use it?
chmod 777 gives read, write, and execute permissions to the owner, group, and all other users. This is generally considered a security risk for most files because anyone on the system can read, modify, or execute the file. It should only be used temporarily for debugging purposes, never in production environments.
How do I recursively change permissions on a directory?
Use chmod -R followed by the permission and directory path. For example, chmod -R 755 /var/www/html changes permissions on the directory and all files within it. Be careful with -R because it applies the same permissions to both files and directories. A safer approach uses find to set different permissions for files (644) and directories (755).
What is the difference between chmod and chown?
chmod changes file permissions (who can read, write, or execute). chown changes file ownership (which user and group owns the file). They work together: chown determines who the "owner" and "group" are, while chmod determines what those users can actually do with the file.
Original Research: Common chmod Permission Settings
I compiled this data from server administration best practices and security guidelines. Last updated March 2026.
| Permission | Symbolic | Use Case |
|---|---|---|
| 644 | rw-r--r-- | Standard files, web content |
| 755 | rwxr-xr-x | Directories, executable scripts |
| 600 | rw------- | Private keys, credential files |
| 700 | rwx------ | Home directories, .ssh folder |
| 444 | r--r--r-- | Read-only config files |
| 775 | rwxrwxr-x | Shared group directories |