How to Enable SSH on Windows Server 2025
Enabling SSH on Windows Server 2025 lets only Administrators and the OpenSSH Users group sign in. You turn it on with PowerShell, then choose who’s in it.

On this page
TL;DR
On Windows Server 2025 the OpenSSH server is installed but not running. In an elevated PowerShell session:
Set-Service -Name sshd -StartupType Automatic
Start-Service -Name sshd
Get-NetFirewallRule -Name 'OpenSSH-Server-In-TCP' |
Format-Table Name, Enabled, ProfileThe stock rule covers the Private profile only. Before connecting, add the profile the server’s network is on; the firewall step below shows how to tell. On a domain-joined server:
Set-NetFirewallRule -Name 'OpenSSH-Server-In-TCP' -Profile Domain, PrivateOn a cloud VM or a workgroup server, whose network is usually Public:
Set-NetFirewallRule -Name 'OpenSSH-Server-In-TCP' -Profile Public, PrivateRun one, not both: -Profile replaces the rule’s list rather than adding to it.
Then connect from a client:
$ ssh Administrator@server-addressIf Set-Service reports that the service does not exist, the capability was
removed from your image; the first step below puts it back.
The visible change from Server 2022 is that the install step is usually gone:
Server 2025 images carry the OpenSSH.Server capability by default. Server
Manager gained a Remote SSH Access toggle on the Local Server page that
enables the service. The commands below do the
same thing from PowerShell, where they can be scripted, and they check each
assumption rather than relying on the image being stock.
Confirm the server capability is present
Get-WindowsCapability -Online | Where-Object Name -like 'OpenSSH*' |
Format-Table Name, StateOn a stock image OpenSSH.Server reads Installed. If it reads NotPresent
— a hardened or minimised image may have dropped it — add it the same way as
on Server 2022:
Add-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0Start sshd and make it start at boot
The service is registered but stopped. Set the start type before starting it, so a reboot cannot leave the server unreachable:
Set-Service -Name sshd -StartupType Automatic
Start-Service -Name sshd
Get-Service -Name sshdThe first start writes the host keys and sshd_config to C:\ProgramData\ssh\.
Confirm the firewall rule
Get-NetFirewallRule -Name 'OpenSSH-Server-In-TCP' -ErrorAction SilentlyContinue |
Format-Table Name, Enabled, Direction, Action, ProfileThe rule is normally present with Enabled set to True. If it is present
but disabled, enable it; if it is absent, create it:
Enable-NetFirewallRule -Name 'OpenSSH-Server-In-TCP'
New-NetFirewallRule -Name 'OpenSSH-Server-In-TCP' -DisplayName 'OpenSSH Server (sshd)' `
-Enabled True -Direction Inbound -Protocol TCP -Action Allow -LocalPort 22Run whichever of the two applies, not both. A rule created this way covers every profile.
The stock rule covers the Private profile only, so check which profile the server’s network is on:
Get-NetConnectionProfile | Format-Table InterfaceAlias, NetworkCategoryA domain-joined server usually reads DomainAuthenticated, and a cloud VM or
a workgroup server usually reads Public. The stock rule admits neither. For
DomainAuthenticated:
Set-NetFirewallRule -Name 'OpenSSH-Server-In-TCP' -Profile Domain, PrivateFor Public:
Set-NetFirewallRule -Name 'OpenSSH-Server-In-TCP' -Profile Public, PrivateRun one, not both: -Profile replaces the rule’s list rather than adding to
it, so the second command would undo the first. A server with more than one
network adapter can report more than one category; then name them all in one
command, such as -Profile Domain, Public, Private.
Public applies the rule on any network the server joins, so on a public address let the network firewall in front of the server decide who reaches port 22.
Connect from a client
$ ssh Administrator@server-addressAccept the host key and enter the account’s Windows password. You arrive in
cmd.exe; that is the default shell for Windows OpenSSH. To land in PowerShell
instead:
New-ItemProperty -Path 'HKLM:\SOFTWARE\OpenSSH' -Name DefaultShell `
-PropertyType String -Force `
-Value 'C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe'Expected result
Get-Service sshd reports Running, something is listening on port 22:
Get-NetTCPConnection -LocalPort 22 -State Listenand a password login from a client succeeds for an administrator. Nobody else can sign in yet, and the next section is why.
Choose who can sign in
On Server 2025, the generated C:\ProgramData\ssh\sshd_config already
limits SSH to two local groups:
AllowGroups administrators "openssh users"This is the change from Server 2022, where the generated file has no such line and every account that can sign in to the server can sign in over SSH. On Server 2025, an account that isn’t an administrator gets in only once it’s a member of OpenSSH Users:
Add-LocalGroupMember -Group 'OpenSSH Users' -Member 'deploy'There is no root account, so PermitRootLogin does nothing. To keep
administrators off SSH entirely, deny their group, which leaves OpenSSH Users
as the only way in:
DenyGroups administratorsAllowUsers narrows access further rather than widening it. An account has to
pass AllowUsers and AllowGroups both, so a name listed in AllowUsers that
isn’t in either group is still refused.
And once key-based login works for the accounts that need it, turn passwords off:
PasswordAuthentication noPut each new line above the Match Group administrators block at the end of
the file. A line added after it belongs to that block: it applies only to
administrators, or, for a directive the block doesn’t allow, stops sshd from
starting.
Restart the service after any change:
Restart-Service -Name sshdWhere an administrator’s public key has to go is the Windows-specific part; the related article scripts it.
Common failures
Administrator gets Permission denied (publickey)
Error
Permission denied (publickey)Windows OpenSSH doesn’t read ~\.ssh\authorized_keys for members of the
Administrators group. The key belongs in
C:\ProgramData\ssh\administrators_authorized_keys, with inheritance removed
and only Administrators and SYSTEM granted access.
sshd stopped while the toggle says on
Refresh Server Manager. If they still disagree, the service failed to start,
and the usual cause is a broken edit to sshd_config. Event Viewer won’t say
so: a broken file leaves the OpenSSH Admin and Operational channels
empty, and the System log records only that the service terminated
unexpectedly. Check the file without starting anything:
sshd -tIt prints the line number and what is wrong with it, and nothing when the file is valid.
Only administrators can sign in
Even after adding an account to OpenSSH Users, on a non-English installation
the group can carry a translated name, such as OpenSSH-Benutzer in German,
while sshd_config still names openssh users. Find the local name, put it in
the AllowGroups line in lower case, quoted if it contains a space, and
restart sshd:
Get-LocalGroup | Where-Object Name -like '*SSH*'Connection times out with the service running
The rule exists but is disabled, or doesn’t cover the network profile the server is on. The firewall drops the packets, so the client waits and times out rather than being refused:
Get-NetFirewallRule -Name 'OpenSSH-Server-In-TCP' | Format-Table Name, Enabled, ProfileEnabled should read True, and Profile must include the profile the
server is on; the firewall step earlier covers both.
Tested with
- OS
- Windows Server 2025 Datacenter (build 26100.33438), OpenSSH.Server removed and added again for a clean install
- OpenSSH
- 9.5p2
- Client
- OpenSSH on macOS 27
- Date
- October 2026