bash: ./script.sh: Permission denied

Fix 'bash: Permission denied' When Running a Script

Script won't run because it lacks execute permission. Fix with chmod +x, check mount options, or adjust shebang.

The 30-Second Fix: Make It Executable

If you're staring at bash: ./script.sh: Permission denied, the culprit is almost always missing execute permission. The fix takes two seconds:

chmod +x script.sh
./script.sh

That's it. If it runs, you're done. This is the #1 cause, especially when you've copied a script from Windows or extracted it from a zip archive.

Why does this happen? By default, new files get permissions like rw-r--r-- (644). That means you can read and write, but not execute. The chmod +x adds execute permission for the owner, group, and others. Simple.

Pro tip: If you see Permission denied for a script you just wrote, check the permissions first with ls -l script.sh. You'll see -rw-r--r-- — missing the x. That's your smoking gun.

The 5-Minute Fix: Check the Shebang and Mount Options

If chmod +x didn't help, or the script still won't run, you're looking at one of two things: a broken shebang or a noexec mount. Let's deal with both.

Broken Shebang

The shebang line (the very first line of the script, like #!/bin/bash) tells the kernel which interpreter to use. If that path is wrong, you'll get a cryptic error. For instance:

#!/usr/bin/env python3
# script content...

If env can't find python3, you'll see env: ‘python3’: No such file or directory — but sometimes you get Permission denied if the interpreter itself is not executable. Check that the interpreter exists and is executable:

which bash
ls -l /bin/bash

Also, make sure the shebang is actually the first line, with no leading spaces or BOM (byte-order mark). A BOM from a Windows text editor will break the shebang and cause weird errors like #!/bin/bash — that will give you bad interpreter: No such file or directory.

noexec Mount

Now the sneaky one. If your script lives on a filesystem mounted with the noexec option, you can't execute any binaries from it — even if permissions are correct. This happens a lot on /tmp or separate data partitions. Check your mounts:

mount | grep noexec

If your script's directory shows up with noexec, you have two options:

  1. Move the script to a partition that allows execution (like /home or /usr/local/bin).
  2. Remount the partition with exec (requires root): mount -o remount,exec /path — but that's temporary and might not survive a reboot.

Real-world trigger: I've seen this bite people on Docker containers and shared hosting where /tmp is noexec. They put a script there, try to run it, and get a confusing permission denied.

The 15-Minute Fix: Dig Deeper When Nothing Else Works

If you've gone through the first two steps and still get Permission denied, it's time to check the usual suspects that only bite after you've eliminated the obvious.

Filesystem ACLs (Access Control Lists)

Standard chmod permissions might be fine, but an access control list could be overriding them. Check with:

getfacl script.sh

If you see entries like user:someuser:--- or mask::r--, an ACL is blocking execution. Remove or adjust the ACL:

setfacl -b script.sh  # remove all ACLs

That resets the ACL and should let the file's regular permissions take over. This is rare on home systems, but on corporate servers with ACL-heavy setups, it's a common gotcha.

SELinux or AppArmor Policies

On RHEL/CentOS and Fedora, SELinux can block script execution even if the file is executable. Check if SELinux is enforced:

getenforce

If it says Enforcing, look at the audit logs:

audit2why -a | grep -i 'denied'

You might see avc: denied { execute } for your script. The fix is usually to set the correct context:

restorecon -v script.sh

Or if it's in a home directory, you might need to adjust the SELinux boolean for user scripts (rare). For AppArmor (Ubuntu), check aa-status and /var/log/syslog for denials. The fix is usually a profile tweak or disabling enforcement for that specific program.

File System Corruption or Quotas

I've seen this once in a blue moon: a file with weird permissions due to filesystem issues. Check for read-only mounts or quota limits:

mount | grep '(ro)'
df -h
quota -u yourusername

If the filesystem is read-only, you can't execute anything new. Remount with rw if it's safe. Quotas are less likely to block execution, but hitting an inode limit can cause weird errors.

One More: Check Your Shell's Hash Table

This is a throwback, but if you've used a command name before the script existed, your shell might have cached the old path. Try

hash -r

or just close and reopen the terminal. It's a long shot, but I've seen it waste 10 minutes of someone's day.

When All Else Fails: Try Running with an Explicit Interpreter

If you're in a bind and just need the script to run regardless of execute permissions, you can bypass the permission check by invoking the interpreter directly:

bash script.sh

Or for Python:

python3 script.py

That works because the kernel isn't executing the script — bash or python3 is. But don't use that as a crutch. Fix the underlying issue, because scripts that need to run via cron or from other contexts will still fail.

Bottom line: 90% of the time it's chmod +x. When it's not, check the shebang and mount options. And if you're on a locked-down corporate box, SELinux and ACLs are your next suspects. That's the whole playbook.

Related Errors in Linux & Unix
ENOSPC Linux 'No space left on device'? Check inodes before you panic Fix apt-get unmet dependencies in Ubuntu 22.04 sudo: unable to resolve host <hostname> Fix 'sudo: unable to resolve host' in Ubuntu 22.04 LTS bash: /usr/bin/command: No such file or directory bash: /usr/bin/command: No such file or directory — fix

Was this solution helpful?

EP
Erropedia Team
Tech Support Editors
The Erropedia editorial team researches and documents real-world tech errors from across Windows, Linux, macOS, networking, databases, cloud platforms, and more. Every solution is reviewed for accuracy and updated as software and systems evolve.