This is the fourth post in a series where I read through man ssh_config and pick out things worth knowing. Previous posts: ObscureKeystrokeTiming, ChannelTimeout, Match version.
Today, we will be looking at the Match sessiontype option. This one was also introduced in OpenSSH 10.0 (April 2025), alongside Match version that I wrote about yesterday. Where Match version lets you branch config based on which OpenSSH you're running, Match sessiontype lets you branch based on what kind of session you're about to start.
From the man page:
The sessiontype keyword matches the requested session type,
which may be one of shell for interactive sessions, exec for
command execution sessions, subsystem for subsystem invocations
such as sftp(1), or none for transport-only sessions, such as
when ssh(1) is started with the -N flag.
There are four possible values: shell, exec, subsystem, and none.
This matters because not all SSH sessions are the same, and you've probably wanted different behavior for different kinds of sessions without having a clean way to express it. Before this, your ssh_config options applied uniformly, the same timeouts, the same forwarding settings, the same keystroke obfuscation, regardless of whether you were opening an interactive shell or just running ssh host rsync ....
Here's a practical example. Say you want ObscureKeystrokeTiming on for interactive sessions (where it's protecting your typing patterns) but off for command execution and file transfers (where it just adds overhead and can interfere with throughput):
Match sessiontype shell
ObscureKeystrokeTiming yes
Match sessiontype exec
ObscureKeystrokeTiming no
Match sessiontype subsystem
ObscureKeystrokeTiming no
Or consider forwarding-only sessions. When you run ssh -N -L 8080:localhost:80 host, you're not opening a shell at all, you're just setting up a tunnel (useful for CERN folks using lxtunnel). The session type here is none. You might want longer timeouts for these since there's no interactive typing to generate traffic, just the forwarded connection:
Match sessiontype none
ServerAliveInterval 60
ServerAliveCountMax 10
And you can combine sessiontype with other Match predicates. If you want specific settings only for sftp to a particular set of hosts:
Match sessiontype subsystem host "storage*.example.com"
Compression yes
The subsystem type covers sftp because sftp is invoked as an SSH subsystem. If you use scp in its newer SFTP mode (which has been the default since OpenSSH 9.0), that also counts as a subsystem session. If you use scp with the legacy SCP/RCP protocol via scp -O, that's a exec session instead, because it runs a remote command.
One thing to note: there's also a SessionTypedirective (not a Match predicate) that's been in ssh_config since OpenSSH 8.7. That one is a setting you apply, it tells ssh what kind of session to request, equivalent to the -N and -s flags. The Match sessiontype predicate is different: it's a condition you test against. The naming overlap is a bit confusing, but they do different things. SessionType none in a Host block means "don't request a shell on this host." Match sessiontype none means "if we're about to start a transport-only session, apply these settings."
The combination of Match version, Match sessiontype, and the existing Match host/Match exec/Match localnetwork predicates makes ssh_config surprisingly expressive now. You can build a single config file that adapts its behavior based on where you're connecting from, what version of OpenSSH you're running, and what you're about to do — all without any external scripting or config generation.