Home / Azure

AzureTroubleshootingIntermediate

Azure Bastion connection fails - fixing RDP/SSH sessions that won't open through Bastion

Bastion sessions fail because of the AzureBastionSubnet NSG, the subnet size, the SKU, a missing permission or the target VM itself. Check them in that order and test with az network bastion ssh.

Deepak Bhardwaj6 min read

Applies toAzure Bastion Basic, Standard and Premium SKUs; Windows and Linux VMs; Azure CLI 2.x with the bastion extension

Symptoms

  • The portal shows "Connecting..." then a blank screen or "The network connection to the Bastion Host appears unstable".
  • "Bastion host could not be reached" or a 403 when you click Connect.
  • Native client (az network bastion ssh / rdp) returns an error about the SKU or the feature not being enabled.
  • RDP opens but you get a credential or "remote computer refused" error.

Most failures fall into five buckets: subnet/NSG, SKU and features, RBAC, the target VM, or the client.

Quick triage table

Symptom Likely cause Fix
Bastion deployment fails Subnet not named AzureBastionSubnet or smaller than /26 Recreate the subnet with the exact name and /26 or larger
Portal session hangs, never connects NSG on AzureBastionSubnet missing required rules Add the inbound/outbound rules below
"Feature not supported" on native client Basic SKU, or native client support not enabled Upgrade to Standard and enable native client support
Connect button greyed out / 403 Missing Reader on VM, NIC or Bastion Grant Reader on the three resources
Session opens then drops VM NSG blocks 3389/22 from the Bastion subnet Allow from the AzureBastionSubnet prefix
Login fails Wrong credentials, account locked, Entra login not configured Reset password or fix the Entra extension

1. Check the subnet

az network vnet subnet show -g rg-hub --vnet-name vnet-hub -n AzureBastionSubnet \
  --query "{prefix:addressPrefix, nsg:networkSecurityGroup.id, rt:routeTable.id}" -o table
  • The name must be exactly AzureBastionSubnet.
  • It must be /26 or larger.
  • Don't attach a route table that sends 0.0.0.0/0 to a firewall. Bastion needs to reach its control plane directly, and a forced-tunnel route on this subnet is a common cause of hanging sessions.

2. Check the NSG on AzureBastionSubnet

An NSG on the Bastion subnet is optional. If you add one, it must contain all of these rules. Missing just one is enough to break sessions.

Direction Source Destination Ports Purpose
Inbound Internet Any 443 User sessions
Inbound GatewayManager Any 443 Control plane
Inbound AzureLoadBalancer Any 443 Health probes
Inbound VirtualNetwork VirtualNetwork 8080, 5701 Bastion data plane
Outbound Any VirtualNetwork 22, 3389 To target VMs
Outbound Any AzureCloud 443 Diagnostics, logging
Outbound VirtualNetwork VirtualNetwork 8080, 5701 Bastion data plane
Outbound Any Internet 80 Session and certificate validation

List what is there now:

az network nsg rule list -g rg-hub --nsg-name nsg-bastion \
  --query "sort_by([], &priority)[].{p:priority,dir:direction,acc:access,src:sourceAddressPrefix,dst:destinationAddressPrefix,ports:destinationPortRange}" -o table

Add a missing rule, for example GatewayManager inbound:

az network nsg rule create -g rg-hub --nsg-name nsg-bastion -n AllowGatewayManager \
  --priority 130 --direction Inbound --access Allow --protocol Tcp \
  --source-address-prefixes GatewayManager --destination-port-ranges 443

Tip

Check the Microsoft "Working with NSG access and Azure Bastion" page for the current rule list before you change production. The rules above match the documented set at the time of writing.

3. Check the target VM's NSG

The VM's NIC or subnet NSG must allow 3389 (Windows) or 22 (Linux) from the AzureBastionSubnet address range, not from the internet.

az network nic list-effective-nsg -g rg-app -n vm-app-01-nic -o json \
  | jq '.value[].effectiveSecurityRules[] | select(.destinationPortRange=="22-22" or .destinationPortRange=="3389-3389")'

4. Check SKU and features

az network bastion show -g rg-hub -n bas-hub \
  --query "{sku:sku.name, native:enableTunneling, ip:enableIpConnect, copy:disableCopyPaste}" -o table
  • Native client (az network bastion ssh/rdp/tunnel) needs Standard or Premium with enableTunneling true.
  • Connecting by IP address (for example to a peered or on-premises machine) needs IP-based connection enabled.
  • Basic SKU only supports the portal experience.

Upgrade and enable native client:

az network bastion update -g rg-hub -n bas-hub --sku Standard --enable-tunneling true

Warning

You can upgrade a SKU but not downgrade it. Plan the change in a maintenance window, because existing sessions drop.

5. Check permissions

The user needs Reader on the VM, the VM's NIC and the Bastion resource (plus the VNet if the VM is in a peered VNet). Without one of these, the Connect button is greyed out or returns a 403.

az role assignment list --assignee user@contoso.com --all \
  --query "[].{role:roleDefinitionName, scope:scope}" -o table

6. Test with the native client

az extension add --name bastion --upgrade

# Linux with SSH key
az network bastion ssh -g rg-hub -n bas-hub \
  --target-resource-id $(az vm show -g rg-app -n vm-app-01 --query id -o tsv) \
  --auth-type ssh-key --username azureuser --ssh-key ~/.ssh/id_rsa

# Windows RDP (runs from a Windows client)
az network bastion rdp -g rg-hub -n bas-hub \
  --target-resource-id $(az vm show -g rg-app -n vm-win-01 --query id -o tsv)

The CLI error message is usually more specific than the portal's.

7. Check the VM itself

If Bastion connects but login fails, the problem is on the VM:

  • RDP disabled, Windows firewall blocking 3389, or the guest is hung. Use Run command or the serial console.
  • For Entra ID login, the AADLoginForWindows / AADSSHLoginForLinux extension must be installed and the user needs the "Virtual Machine Administrator Login" or "Virtual Machine User Login" role.
az vm run-command invoke -g rg-app -n vm-win-01 --command-id RunPowerShellScript \
  --scripts "Get-NetFirewallRule -DisplayGroup 'Remote Desktop' | Select DisplayName,Enabled"

Prevent it next time

  • Deploy Bastion and its NSG from a template that already contains the required rules.
  • Keep forced-tunnel route tables off AzureBastionSubnet.
  • Grant Bastion access through a group that has Reader on the hub and spoke resource groups.
  • Turn on Bastion diagnostic logs (BastionAuditLogs) to see who connected and where.

Checklist

  • Subnet named AzureBastionSubnet, /26 or larger, no forced tunnelling
  • NSG rules complete (or no NSG)
  • VM NSG allows 22/3389 from the Bastion subnet
  • SKU and native client support match how users connect
  • Reader on VM, NIC and Bastion
  • Guest OS accepts RDP/SSH