How to allow or deny SSH access for users and groups

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.

Steps to allow or deny SSH access for users and groups:

  1. Open a terminal on the server with an account that can run sudo, and keep that session connected until the new policy is verified.
    $ whoami
    user

    Do not close the current administrative session until a second SSH login confirms that the new rules work.

  2. Check whether the server loads SSH configuration snippets before choosing the file to edit.
    $ 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.

  3. Confirm the exact login and group names that the SSH policy will reference.
    $ 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.

  4. Create or edit the file that will hold the SSH access policy.
    $ 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.

  5. Add the user and group rules that should control SSH logins.
    # 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.

  6. Test the SSH daemon configuration before reloading the service.
    $ sudo sshd -t

    No output means the full configuration parsed successfully.

  7. Inspect the resolved allow and deny directives that sshd will apply after includes are merged.
    $ 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.

  8. Reload the SSH service so the new access policy takes effect without a full daemon restart.
    $ 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.

  9. Check that the SSH service stayed active after the reload.
    $ 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.

  10. From a second terminal, confirm that an allowed account can still open a new SSH session.
    $ ssh user@host.example.net 'id -un'
    user
  11. From another fresh SSH attempt, confirm that a denied account or group is refused before closing the original session.
    $ 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.