TechEarl

Show an SSH Login Banner Before Authentication

Set an SSH login banner that shows before authentication with the Banner directive in sshd_config. The difference from /etc/motd, the config, and the caveats.

Ishan Karunaratne⏱️ 9 min readUpdated
Share thisCopied
Set an SSH login banner that appears before password or key authentication using the Banner directive in sshd_config. How it differs from /etc/motd, and the gotchas.

To show a message before someone authenticates over SSH, point the Banner directive in sshd_config at a file:

bash
# in /etc/ssh/sshd_config
Banner /etc/ssh/banner.txt

Write your text into /etc/ssh/banner.txt, reload sshd, and the next person who connects sees that text before the password or key prompt. That is the whole job. The part people get wrong is which file does this: /etc/motd prints after you log in, the Banner file prints before authentication. If the goal is a legal "authorized use only" notice that an attacker sees before they are in, you want Banner, not motd.

The config, end to end

Three steps: write the banner text, register it, reload the daemon.

First the text. Keep it plain ASCII; the banner is sent raw to the client's terminal before any session exists, so fancy escape sequences are a bad idea.

bash
sudo tee /etc/ssh/banner.txt > /dev/null <<'EOF'
***************************************************************************
                            AUTHORIZED ACCESS ONLY
  This system is restricted to authorized users. All activity is logged
  and monitored. Unauthorized access is prohibited and will be prosecuted.
***************************************************************************
EOF

Then point sshd at it. Edit /etc/ssh/sshd_config and add (or uncomment) the line:

bash
Banner /etc/ssh/banner.txt

The default is Banner none, which is why a stock server shows nothing before the prompt. Set it to an absolute path. Relative paths are not resolved against anything useful, so always give the full path.

I used /etc/ssh/banner.txt here, but the traditional file for a pre-login message is /etc/issue.net, and you will see plenty of guides point Banner at that. Either works; Banner does not care what the file is called. The one thing to know is that /etc/issue.net is also consumed by the local login stack for console logins, so if you only want the text on SSH connections, a dedicated file like /etc/ssh/banner.txt keeps the two concerns separate.

Then reload. This is a config-only change, so a reload is enough; you do not need a full restart that would drop existing sessions:

bash
sudo systemctl reload ssh     # Debian/Ubuntu: the unit is "ssh"
sudo systemctl reload sshd    # RHEL/Fedora/Rocky/Alma: the unit is "sshd"

Before reloading anything on a box you care about, validate the config so a typo does not lock out the daemon:

bash
sudo sshd -t

No output means the config parses. If it complains, fix it before you reload.

What it looks like from the client side

Connect and the banner lands before the password prompt:

text
$ ssh techearl@server.example
***************************************************************************
                            AUTHORIZED ACCESS ONLY
  This system is restricted to authorized users. All activity is logged
  and monitored. Unauthorized access is prohibited and will be prosecuted.
***************************************************************************
techearl@server.example's password:

The banner is printed by the server during the SSH protocol's pre-auth phase, so it shows even on a connection that then fails authentication. That is the point of it: a notice that is delivered to anyone who reaches the daemon, before they prove who they are.

An SSH connection probed with PreferredAuthentications=none showing the AUTHORIZED ACCESS ONLY banner, followed by Permission denied, proving the banner is delivered before and independent of authentication
Probed with PreferredAuthentications=none (no credentials offered), the server still sends the banner, then denies access. Proof the banner reaches a client before it authenticates. Real output against a configured sshd.

This is the distinction that trips everyone up. They are different files, set in different places, shown at different moments.

Banner (sshd_config)/etc/motd
When it showsBefore authenticationAfter successful login
Configured in/etc/ssh/sshd_config (Banner /path)The file /etc/motd itself
Who controls itSSH daemonThe login/PAM stack (pam_motd)
Seen by failed loginsYesNo
Typical useLegal "authorized use only" noticeWelcome text, host info, update reminders
Applies toSSH connections onlyEvery login (SSH, console, etc.)

So if you want every visitor warned regardless of whether they get in, that is Banner. If you want a greeting or system status for users who are already through, that is motd. Plenty of hardened servers set both: a stern pre-auth banner and a quieter post-login motd. The same warning-notice idea shows up one layer down, too: you can customize the sudo lecture so a policy message lands the first time a user reaches for elevated privileges.

One more wrinkle on the client side. The OpenSSH client prints the banner to stderr, so it shows up even when you run a non-interactive remote command (only stdout gets piped, not stderr). The connecting user can suppress it locally with LogLevel QUIET in their ~/.ssh/config. So treat the banner as a notice you are presenting, not as something you can guarantee a remote script reads or acts on.

Per-group or per-source banners with Match

If you want a different banner for connections from a particular address, user, or group, wrap a second Banner in a Match block. Match blocks live at the end of sshd_config, since everything after a Match line belongs to that conditional until the next Match or end of file:

bash
Banner /etc/ssh/banner.txt

Match Address 10.0.0.0/8
    Banner /etc/ssh/banner-internal.txt

Connections from the 10.0.0.0/8 range get the internal banner; everyone else gets the default one set above. The same works with Match User, Match Group, and so on. Keep the global Banner line above the first Match so it acts as the fallback.

Caveats worth knowing

The banner is pre-auth and unauthenticated, which has consequences:

  • It leaks to anyone who can reach the port. Port scanners, bots, and curious strangers all see it. Do not put hostnames, OS versions, internal IPs, or contact names in it. "Authorized access only" is fine; "prod-db-03 running Ubuntu 22.04, call Dave at..." is an information disclosure.
  • It does not stop anyone. A banner is a legal and policy device, not a security control. It deters nobody technically. Pair it with real hardening: disable password authentication and turn off direct root login. Once those are in place, audit what your daemon actually offers to confirm the config is as tight as you think.
  • Cloud images sometimes pre-set it. Some AWS, GCP, and Azure base images ship a Banner or a dynamic motd already. Check what is there before adding your own so you do not end up with two notices stacked.
  • Keep it ASCII and short. It is sent raw to the terminal before the session exists. Box-drawing with UTF-8 can render as garbage on minimal clients; long banners just annoy the humans who log in fifty times a day.
  • File-transfer tools discard it. The server still sends the banner during the pre-auth handshake, but sftp and scp clients typically suppress or ignore it rather than print it, so do not rely on it surfacing in an automated transfer.

When not to bother

If the box is your own laptop or a single-user dev VM that nobody else touches, a pre-auth banner is just noise you scroll past. Banners earn their place on shared, internet-facing, or compliance-scoped servers, the ones where "we displayed a notice that access was restricted" is a sentence someone might actually need to say later. For a personal machine, skip it and spend the effort on key-only auth instead.

See also

Sources

Authoritative references this article was fact-checked against.

TagsSSHsshdBannerLogin BannerLinuxSecuritysystem-administration

Found this useful? Pass it on.

Copied

Ishan Karunaratne

Software Systems Architect · Senior Software Engineer · Engineering Leadership

Software systems architect and senior software engineer with more than two decades designing, building, and running production software, Linux systems, and DevOps infrastructure, and lately working AI into the stack. Now a CTO, though what I write here is drawn from the full arc of that work, across architecture, engineering, and operations, not any single job.

Keep reading

Related posts

Use grep -C 3 'pattern' file to print 3 lines before and after each match. The -A, -B, -C context flags, the -- group separator, asymmetric context, recursive search, and BSD vs GNU grep differences.

How to Show Lines Before and After a grep Match (Context)

grep -C 3 'pattern' file prints the matching line plus 3 lines on each side. The three context flags (-A after, -B before, -C both), how the -- group separator works between match blocks, asymmetric context, recursive context search, and the macOS BSD vs GNU differences that bite.

Connect to an AWS EC2 instance using plain SSH with a key pair, EC2 Instance Connect, AWS Systems Manager Session Manager, or an EC2 Instance Connect Endpoint for private instances. Default usernames, security group rules, and troubleshooting Permission denied and Connection timed out.

How to SSH into an AWS EC2 Instance

Connect to an EC2 instance four ways: plain SSH with a key pair, EC2 Instance Connect, Session Manager, and EC2 Instance Connect Endpoint. Default usernames, security group rules, and the troubleshooting matrix that fixes Permission denied and Connection timed out.