Fix SSH “User Not Allowed Because Shell Does Not Exist”

A minimalist flat vector illustration showing a gold Linux terminal icon being repaired by a lime green wrench on a purple background.

We may earn a referral fee at no additional cost to you when you shop through the links on this page.

You type the right password, but SSH still throws you out, and the server’s auth log shows the login was “not allowed because shell /bin/zsh does not exist”. The password was never the problem: the account’s login shell is missing or invalid, so sshd refuses the session. This DevAnswers fix points the user back at a real shell.

Quick fix: give the user a valid shell 

The affected user cannot SSH in, so you need another way onto the box first: the provider’s console / recovery shell, or a second account that still has access. Run the fix from there with sudo.

No console and this is your only account? Most cloud providers (DigitalOcean, Linode, AWS, Hetzner) expose a web-based serial console or recovery mode from their dashboard that logs you in without SSH, that is where you run the fix.

Set the user’s login shell back to a real one with usermod:

Terminal
sudo usermod -s /bin/bash billy

That rewrites the last field of the user’s /etc/passwd entry. No service restart is needed, the next SSH login uses the new shell immediately.

If you need to check other accounts for the same problem, list all users on Linux covers it.

Why SSH rejects a missing shell 

When you connect, sshd looks up the account in /etc/passwd and checks its login shell. If that shell does not exist on disk or is not executable, sshd refuses the login outright, with the correct password, rather than dropping you into something broken. That is the “not allowed because shell … does not exist” message.

You can confirm that is the cause by reading the SSH log. On a systemd system use journalctl (the unit is ssh on Debian and Ubuntu, sshd on RHEL-family systems); otherwise the message is in /var/log/auth.log, or /var/log/secure on RHEL:

Terminal
sudo journalctl -u ssh -n 20 | grep -i shell
Output
sshd[812]: User billy not allowed because shell /bin/zsh does not exist

It usually happens after the shell binary was removed (you uninstalled zsh or fish but a user still pointed at it), a typo crept into /etc/passwd, or a script set the shell to a path that was never there.

If getent shows a shell that genuinely exists and you are still locked out, the cause is something else, an AllowUsers or DenyUsers rule in sshd_config, a locked (passwd -l) or expired account, or a PAM restriction. Those are separate issues from this one; this fix is specifically for the missing-shell message.

Check the user’s current shell 

To pin down the culprit before you fix it (or on another affected account), look at the user’s record, the field after the home directory is the login shell. Each line is seven colon-separated fields, name, password placeholder, UID, GID, comment, home directory, and finally the login shell, so it is always the last one that matters here:

Terminal
getent passwd billy
Output
billy:x:1001:1001::/home/billy:/bin/zsh

Here the shell is /bin/zsh, which is missing. Compare it against the list of valid login shells the system knows about:

Terminal
cat /etc/shells
Output
/bin/sh
/bin/bash
/usr/bin/bash
/bin/dash
/usr/bin/dash

Pick any path that actually exists on the box, /bin/bash is the safe default. Whatever you pick must both exist and be executable; a path that is present but has lost its execute bit fails the same way. If you are unsure where a shell lives, command -v bash prints its real path (it can be /bin/bash or /usr/bin/bash). (chsh will only let a non-root user choose a shell listed in /etc/shells; usermod as root is not restricted, so use a real path.)

nologin vs a broken shell 

One trap: /usr/sbin/nologin (or /sbin/nologin on some systems, confirm with command -v nologin) is not a missing shell. It is a real, valid program that deliberately refuses an interactive login and prints a polite message. Service accounts use it on purpose so they can own files and run daemons without anyone logging in as them.

So “denied on purpose” (nologin) and “shell does not exist” (a dangling path) are different problems. If you actually want to block a human, set nologin intentionally:

Terminal
sudo usermod -s /usr/sbin/nologin serviceuser

If you want the user to log in, point them at a shell that exists, not nologin and not a path that was deleted.

Verify the Fix 

From your own machine, connect as the fixed user:

Terminal
ssh billy@your-server
Output
billy@your-server:~$

Landing at a shell prompt means it worked. If you are still rejected, re-run getent passwd billy to confirm the shell path stuck and that the file is actually executable (ls -l /bin/bash). More generally, whenever you change any account’s shell, including your own, keep an existing session open and test the new login from a second terminal, so a typo never locks anyone out.

Support DevAnswers
Written, tested and maintained by one developer. Your support keeps these guides accurate and ad-light.
Buy me a coffee

1 reply

Leave a reply

  1. MrPoopyButthole

    THANK YOU THANK YOU THANK YOU!!! This has been driving me f****** crazy all morning!!

    This fixed my issue on OpenVPN AS