Limiting which accounts and Unix groups can log in over SSH reduces the number of identities that can reach a shell on a server. That is useful on shared Linux hosts, bastion systems, and long-lived servers where old local users or broad administrative groups can otherwise remain a working remote-access path.
The OpenSSH server evaluates access-control directives from /etc/ssh/sshd_config and any included snippets before it finishes authentication. DenyUsers and AllowUsers match login names, while DenyGroups and AllowGroups match a user's primary or supplementary Unix groups. Current Ubuntu packages load /etc/ssh/sshd_config.d/*.conf from the top of the main configuration file, so a dedicated drop-in file is usually the cleanest place to keep user and group access rules.
Because an SSH access mistake can lock out remote administration immediately, keep the current session open until a second login test succeeds. The deny lists are processed before the allow lists, and when both AllowUsers and AllowGroups are present, a login must satisfy both allow rules to succeed. If the access policy also depends on source networks or other connection attributes, use Match blocks instead of stretching one long allow or deny list.
$ whoami user
Do not close the current administrative session until a second SSH login confirms that the new rules work.
$ sudo grep -n '^Include' /etc/ssh/sshd_config 1:Include /etc/ssh/sshd_config.d/*.conf
If the host does not use an /etc/ssh/sshd_config.d/ include directory, place the same directives near the end of /etc/ssh/sshd_config instead.
$ id user uid=1000(user) gid=1000(user) groups=1000(user),27(sudo)
Run the same check for each account in the policy. AllowUsers and DenyUsers match login names, while AllowGroups and DenyGroups match local group names.
$ sudo vi /etc/ssh/sshd_config.d/60-access-control.conf
If step 2 showed no include directory, edit /etc/ssh/sshd_config instead. Keeping the access rules in one file makes later reviews and rollbacks easier.
# Allow only approved administrator accounts AllowUsers user backupuser # Deny one account even if another rule would otherwise allow it DenyUsers deploy # Require allowed logins to belong to the admin group AllowGroups sudo # Block members of a restricted group DenyGroups contractors
OpenSSH processes DenyUsers before AllowUsers and DenyGroups before AllowGroups. If both AllowUsers and AllowGroups are present, a successful login must satisfy both allow lists.
Prefer exact account and group names first. Use Match blocks when the policy also needs source-address or per-subnet conditions.
$ sudo sshd -t
No output means the full configuration parsed successfully.
Related: How to test SSH server configuration
$ sudo sshd -T ##### snipped ##### allowusers user allowusers backupuser denyusers deploy allowgroups sudo denygroups contractors ##### snipped #####
sshd -T prints the effective runtime configuration, and repeated values appear as separate output lines.
Related: How to view SSH server configuration
$ sudo systemctl reload ssh
Use sudo systemctl reload sshd on systems where the service unit is sshd instead of ssh. If the unit does not support reload, fall back to a restart only after the syntax test succeeds.
$ sudo systemctl status ssh --no-pager
● ssh.service - OpenBSD Secure Shell server
Loaded: loaded (/usr/lib/systemd/system/ssh.service; enabled; preset: enabled)
Active: active (running) since Tue 2026-04-14 12:41:10 +08; 3s ago
TriggeredBy: ● ssh.socket
Docs: man:sshd(8)
man:sshd_config(5)
##### snipped #####
If the unit does not return active (running), stop and inspect the journal before opening a new SSH session.
$ ssh user@host.example.net 'id -un' user
$ ssh deploy@host.example.net 'id -un' deploy@host.example.net: Permission denied (publickey,password).
If DenyGroups is in use, repeat the same check with a user who belongs to the blocked group.