Fix 'permission denied' on Linux scripts & files

Permission denied when running a script? Check execute bit, filesystem mount options, then ownership. Here's the order to fix it.

Cause #1: Missing execute permission on the file

What's actually happening here is the kernel checks the file's mode bits when you try to exec it. If the execute bit (owner, group, or other) isn't set, you get bash: ./script.sh: Permission denied. This is the most common cause, especially after you download a script or copy it from a Windows machine (where there's no concept of an execute bit).

ls -l script.sh
# -rw-r--r-- 1 user user 1234 Jan 1 10:00 script.sh   <- no x bits

The fix is to add the execute bit. I usually go with chmod 755 for scripts I want others to read and run, or chmod +x if you only care about your own user. The reason +x works is it adds execute for owner, group, and other based on your umask, but 755 is explicit and predictable.

chmod +x script.sh
# or
chmod 755 script.sh
./script.sh

Real-world trigger: You just pulled a repo from GitHub, and bin/deploy.sh won't run. Git does store the execute bit, but if the file was added on Windows or the repo doesn't have it set, you'll hit this.

If you're on a filesystem that doesn't support Unix permissions (like a FAT32 USB drive), chmod won't stick. In that case, copy the script to your home directory (ext4 or similar) and run it there. That's not a workaround—it's the actual fix, because FAT32 has no concept of mode bits.

Cause #2: Filesystem mounted with noexec

This one sneaks up on you. The file has the execute bit, but the mount options block execution. When a filesystem is mounted with noexec, the kernel refuses to run any binary or script from that mount, regardless of permissions. You'll see Permission denied even as root, which is a clue.

Common culprits: /tmp, /home on some hardened setups, or mounted external drives. Check with mount or findmnt:

findmnt /tmp
# TARGET SOURCE FSTYPE OPTIONS
# /tmp   /dev/sda1 ext4 rw,noexec,relatime

If you see noexec in OPTIONS, that's your problem. You have two paths: remount without noexec, or move the script to a location that allows execution. For a quick test, remount:

sudo mount -o remount,exec /tmp

The reason this works is remount changes the mount flags on the fly. But be careful—if noexec was set by a security policy (like on a corporate laptop or a server with SELinux/AppArmor), you might not want to disable it. In that case, put your scripts in /usr/local/bin or your home directory, which is usually mounted with exec.

I've seen this bite people who mount their entire home directory with nodev,noexec for security and then wonder why ./miniconda.sh fails. The installer is trying to execute a shell script from $HOME. Move it to /tmp (if that's exec) or remount.

Cause #3: Root squash on NFS or ownership mismatch

Less common if you're a solo user, but on NFS mounts this is a classic. When an NFS server exports a share with root_squash, the root user on the client is mapped to the anonymous user (nobody). So even if you have the execute bit and the file is owned by root, your client-side root can't run it because the server sees you as 'nobody' with no permissions.

That's the theory. The symptom: sudo ./app fails with Permission denied, but ls -l shows -rwxr-xr-x and you're root. You check ownership and it says root root. But on the server, the file might be owned by a different UID that doesn't map.

First, verify it's NFS:

mount | grep nfs
# server:/export on /mnt/data type nfs4 (rw,relatime,vers=4.2)

Then check the actual ownership from the client's perspective. If UIDs don't match (client UID 1000 vs server UID 1001), you'll get weird permission errors. The fix is either:

  • Align UIDs across systems (use the same UID for the same user).
  • Ask the server admin to add no_root_squash for your client IP—but that's a security risk, so only if you control the server.
  • Use sudo -u nobody? No, that's wrong. The real fix is to fix the mapping.

I ran into this on a cluster where compute nodes mounted /home via NFS. Users could compile but not run their own binaries because the automounter used squash. The fix was to ensure all nodes had the same UID/GID database (via LDAP or manual passwd entries).

If you're not on NFS, ownership mismatch can still happen if a file is owned by another user and you lack read/execute. But if you're root, that shouldn't stop you—except, as above, when root_squash is in play.

Quick-reference summary

CauseSymptomCheckFix
No execute bitPermission denied for your user, works with bash script.shls -l shows no xchmod +x file
noexec mountFails even as root, file has x bitfindmnt /path shows noexecmount -o remount,exec /path or move file
NFS root_squash / UID mismatchFails as root on NFS, file has x bitmount | grep nfs and id on serverAlign UIDs or adjust export options

That's the order I'd run through. Start with chmod, because nine times out of ten that's it. Move to mount options if you're on /tmp or an external drive. Only start blaming NFS when you're sure the first two are clean.

Related Errors in Linux & Unix
VLC Codec Not Supported Fix on Linux Uncaught EvalError: Refused to evaluate a string as JavaScript JS eval error on Google search? Here's the real fix E: dpkg was interrupted Fix dpkg Interrupted Error: Run dpkg --configure -a Linux Display Stuck at 800x600 After Update? Fix Here

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.