What's Actually Happening
Azure VMs become inaccessible when network security groups block traffic, the VM is in a failed state, or DNS and IP configuration is incorrect. SSH or RDP connections fail.
The Error You'll See
SSH timeout:
```bash $ ssh azureuser@my-vm.eastus.cloudapp.azure.com
ssh: connect to host my-vm.eastus.cloudapp.azure.com port 22: Connection timed out ```
RDP error:
Remote Desktop can't connect to the remote computer for one of these reasons:
1) Remote access to the server is not enabled
2) The remote computer is turned off
3) The remote computer is not available on the networkConnection refused:
```bash $ ssh azureuser@20.50.100.200
ssh: connect to host 20.50.100.200 port 22: Connection refused ```
Why This Happens
- 1.NSG blocking - Security group rules not allowing traffic
- 2.VM stopped - VM deallocated or stopped
- 3.No public IP - Missing or removed public IP
- 4.DNS issue - DNS name not resolving
- 5.Just-in-time access - JIT VM access blocking
- 6.Firewall rules - Azure Firewall blocking traffic
Step 1: Check VM Status
```bash # Check VM status az vm show --resource-group myRG --name myVM --query "{powerState: powerState, provisioningState: provisioningState}" -o table
# Check VM power state az vm get-instance-view --resource-group myRG --name myVM --query "instanceView.statuses[?code=='PowerState/running']" -o table
# List all VMs and status az vm list --query "[].{Name:name, ResourceGroup:resourceGroup, PowerState:powerState}" -o table
# Start VM if stopped az vm start --resource-group myRG --name myVM
# Check VM exists az vm list --query "[?name=='myVM']" -o table
# Get VM details az vm show --resource-group myRG --name myVM ```
Step 2: Check Public IP
```bash # Get public IP of VM az vm show --resource-group myRG --name myVM --query "networkProfile.networkInterfaces[0].id" -o tsv | xargs -I {} az network nic show --ids {} --query "ipConfigurations[0].publicIPAddress.id" -o tsv | xargs -I {} az network public-ip show --ids {} --query "ipAddress" -o tsv
# Or simpler: az vm list-ip-addresses --resource-group myRG --name myVM -o table
# Check if public IP exists az network public-ip list --resource-group myRG -o table
# Create public IP if missing az network public-ip create --resource-group myRG --name myPublicIP
# Associate with NIC az network nic ip-config update --resource-group myRG --nic-name myNIC --name ipconfig1 --public-ip-address myPublicIP
# Check DNS name az network public-ip show --resource-group myRG --name myPublicIP --query "dnsSettings.fqdn" -o tsv
# Set DNS name az network public-ip update --resource-group myRG --name myPublicIP --dns-name my-vm-dns ```
Step 3: Check Network Security Group
```bash # List NSG rules az network nsg rule list --resource-group myRG --nsg-name myNSG -o table
# Check NSG allows SSH (port 22) az network nsg rule show --resource-group myRG --nsg-name myNSG --name AllowSSH -o json
# Create SSH rule az network nsg rule create \ --resource-group myRG \ --nsg-name myNSG \ --name AllowSSH \ --protocol Tcp \ --priority 100 \ --destination-port-range 22 \ --source-address-prefixes '*' \ --access Allow
# Create RDP rule az network nsg rule create \ --resource-group myRG \ --nsg-name myNSG \ --name AllowRDP \ --protocol Tcp \ --priority 110 \ --destination-port-range 3389 \ --source-address-prefixes '*' \ --access Allow
# Or allow only from your IP MY_IP=$(curl -s ifconfig.me) az network nsg rule create \ --resource-group myRG \ --nsg-name myNSG \ --name AllowSSHFromMyIP \ --protocol Tcp \ --priority 100 \ --destination-port-range 22 \ --source-address-prefixes $MY_IP/32 \ --access Allow ```
Step 4: Check NSG Association
```bash # Check NSG associated with subnet az network vnet subnet show --resource-group myRG --vnet-name myVNet --name default --query "networkSecurityGroup.id" -o tsv
# Check NSG associated with NIC az network nic show --resource-group myRG --name myNIC --query "networkSecurityGroup.id" -o tsv
# Associate NSG with NIC az network nic update --resource-group myRG --name myNIC --network-security-group myNSG
# Associate NSG with subnet az network vnet subnet update --resource-group myRG --vnet-name myVNet --name default --network-security-group myNSG
# Verify NSG flow logs az network watcher flow-log show --resource-group myRG --nsg myNSG ```
Step 5: Test Network Connectivity
```bash # Test with Network Watcher IP flow az network watcher test-ip-flow \ --resource-group myRG \ --direction Inbound \ --protocol TCP \ --local 20.50.100.200:22 \ --remote 1.2.3.4:12345 \ --vm myVM
# Check next hop az network watcher show-next-hop \ --resource-group myRG \ --vm myVM \ --source-ip 10.0.0.4 \ --dest-ip 8.8.8.8
# Test connectivity az network watcher test-connectivity \ --resource-group myRG \ --source-resource myVM \ --dest-address 8.8.8.8 \ --protocol TCP \ --dest-port 80
# Use NSG flow logs to see blocked traffic # In Azure Portal: Network Watcher > NSG Flow Logs ```
Step 6: Check Just-In-Time Access
```bash # Check if JIT is enabled az security jit-policy list -o table
# Request JIT access az security jit-policy request \ --resource-group myRG \ --location eastus \ --name myJITPolicy \ --vm myVM \ --port 22 \ --protocol TCP \ --duration PT2H \ --source-ip 1.2.3.4
# If JIT is blocking, you must request access before connecting
# List JIT policies az security jit-policy list -o table
# Disable JIT if not needed # Via Azure Portal: Security Center > Just-in-time VM access ```
Step 7: Check Azure Firewall
```bash # Check if Azure Firewall exists az network firewall list -o table
# Check firewall rules az network firewall rule list --resource-group myRG --firewall-name myFirewall --collection-name myCollection -o table
# Check NAT rules for inbound access az network firewall nat-rule list --resource-group myRG --firewall-name myFirewall -o table
# Add DNAT rule for SSH az network firewall nat-rule create \ --resource-group myRG \ --firewall-name myFirewall \ --collection-name myDNATCollection \ --name AllowSSH \ --protocols Tcp \ --source-addresses '*' \ --destination-addresses 20.50.100.200 \ --destination-ports 22 \ --translated-address 10.0.0.4 \ --translated-port 22
# Check network rules az network firewall network-rule list --resource-group myRG --firewall-name myFirewall -o table ```
Step 8: Reset SSH Configuration
```bash # Reset SSH configuration az vm user reset-ssh --resource-group myRG --name myVM
# Reset SSH access az vm run-command invoke \ --resource-group myRG \ --name myVM \ --command-id RunShellScript \ --scripts "sudo service sshd restart"
# Reset user password/SSH key az vm user update \ --resource-group myRG \ --name myVM \ --username azureuser \ --ssh-key-value @~/.ssh/id_rsa.pub
# Use serial console for troubleshooting # Azure Portal: VM > Support + troubleshooting > Serial console
# Or via run-command az vm run-command invoke \ --resource-group myRG \ --name myVM \ --command-id RunShellScript \ --scripts "cat /var/log/auth.log | tail -50" ```
Step 9: Use Boot Diagnostics
```bash # Enable boot diagnostics az vm boot-diagnostics enable --resource-group myRG --name myVM --storage $STORAGE_ACCOUNT
# Get boot diagnostics screenshot az vm boot-diagnostics get-boot-log --resource-group myRG --name myVM
# Or view in Azure Portal: # VM > Support + troubleshooting > Boot diagnostics
# Check VM extension status az vm extension list --resource-group myRG --vm-name myVM -o table
# Redeploy VM to another host az vm redeploy --resource-group myRG --name myVM ```
Step 10: Monitor VM Connectivity
```bash # Create connectivity monitor az network watcher connection-monitor create \ --resource-group myRG \ --location eastus \ --name myMonitor \ --source-resource myVM \ --dest-address 8.8.8.8 \ --dest-port 80
# Query connectivity monitor az network watcher connection-monitor query --resource-group myRG --name myMonitor
# Check VM metrics az monitor metrics list \ --resource /subscriptions/.../resourceGroups/myRG/providers/Microsoft.Compute/virtualMachines/myVM \ --metric "Percentage CPU,Network In,Network Out" \ --aggregation Average \ --start-time 2026-04-15T00:00:00Z \ --end-time 2026-04-16T00:00:00Z
# Create alert for unreachable VM az monitor metrics alert create \ --name "VM-Not-Responding" \ --resource-group myRG \ --scopes /subscriptions/.../resourceGroups/myRG/providers/Microsoft.Compute/virtualMachines/myVM \ --condition "avg Percentage CPU < 1" \ --evaluation-frequency 5m \ --window-size 15m ```
Azure VM Accessibility Checklist
| Check | Command | Expected |
|---|---|---|
| VM running | az vm show | PowerState/running |
| Public IP | az vm list-ip-addresses | IP shown |
| NSG rule | az network nsg rule list | Allow SSH/RDP |
| NSG association | az network nic show | NSG linked |
| JIT access | az security jit-policy list | Access granted |
Verify the Fix
```bash # After fixing NSG, IP, or VM status
# 1. Check VM running az vm show --resource-group myRG --name myVM --query "powerState" -o tsv # Should return: VM running
# 2. Get public IP az vm list-ip-addresses --resource-group myRG --name myVM -o table
# 3. Test SSH ssh azureuser@<public-ip> # Should connect
# 4. Test port connectivity nc -zv <public-ip> 22 # Should succeed
# 5. Check NSG rules az network nsg rule list --resource-group myRG --nsg-name myNSG --query "[?destinationPortRange=='22']" -o table
# 6. Verify from browser # For web VMs, access http(s)://<public-ip> ```
Related Issues
- [Fix Azure NSG Rules Not Working](/articles/fix-azure-nsg-rules-not-working)
- [Fix Azure VM SSH Permission Denied](/articles/fix-azure-vm-ssh-permission-denied)
- [Fix Azure Public IP Not Working](/articles/fix-azure-public-ip-not-working)