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
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:
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:
sudo journalctl -u ssh -n 20 | grep -i shell
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:
getent passwd billy
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:
cat /etc/shells
/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:
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:
ssh billy@your-server
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.
THANK YOU THANK YOU THANK YOU!!! This has been driving me f****** crazy all morning!!
This fixed my issue on OpenVPN AS