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:

bash
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 network

Connection refused:

```bash $ ssh azureuser@20.50.100.200

ssh: connect to host 20.50.100.200 port 22: Connection refused ```

Why This Happens

  1. 1.NSG blocking - Security group rules not allowing traffic
  2. 2.VM stopped - VM deallocated or stopped
  3. 3.No public IP - Missing or removed public IP
  4. 4.DNS issue - DNS name not resolving
  5. 5.Just-in-time access - JIT VM access blocking
  6. 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

CheckCommandExpected
VM runningaz vm showPowerState/running
Public IPaz vm list-ip-addressesIP shown
NSG ruleaz network nsg rule listAllow SSH/RDP
NSG associationaz network nic showNSG linked
JIT accessaz security jit-policy listAccess 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> ```

  • [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)