Load Balancer Backend Unhealthy in Azure
When Azure Load Balancer or Application Gateway marks backend pool members as unhealthy, traffic stops routing to those instances and your application becomes degraded or unavailable. This page explains how health probes work, the most common reasons they fail, and the diagnostic steps to identify and fix each cause.
How Load Balancer health probes work
Azure Standard Load Balancer sends periodic probes to each backend VM to determine if it can receive traffic. Two probe types are available:
- TCP probe: opens a TCP connection to the specified port. If the connection succeeds (the three-way handshake completes), the backend is healthy. The application does not need to send any data.
- HTTP/HTTPS probe: sends an HTTP GET request to the specified path and port. The backend is healthy only if it returns HTTP 200. Any other response code — including 301, 404, or 500 — marks it as unhealthy.
All probes originate from the special Azure platform IP 168.63.129.16. This IP is not routable and cannot be blocked by route tables, but it can be blocked by NSG rules. NSGs are the most common cause of probe failures.
Check current probe configuration on a load balancer:
az network lb probe list \
--resource-group myResourceGroup \
--lb-name myLoadBalancer \
--output tableSample output:
IntervalInSeconds Name NumberOfProbes Port Protocol
------------------- ----------- ---------------- ------ ----------
15 httpProbe 2 80 HttpView backend pool members:
az network lb address-pool list \
--resource-group myResourceGroup \
--lb-name myLoadBalancer \
--output jsonCause 1: NSG blocking the health probe source IP
The most common cause of all backends showing as unhealthy simultaneously is an NSG rule that blocks inbound traffic from 168.63.129.16. This happens when an engineer adds a hardening rule like DenyAllInbound without including an exception for the Azure platform IP.
Check the NSG rules on the backend subnet or NIC:
az network nsg rule list \
--resource-group myResourceGroup \
--nsg-name myBackendNSG \
--output tableLook for any Deny rule with a lower priority number (higher precedence) that could block the probe traffic. Add an explicit allow rule for the health probe source:
az network nsg rule create \
--resource-group myResourceGroup \
--nsg-name myBackendNSG \
--name AllowAzureLoadBalancerInBound \
--priority 100 \
--protocol Tcp \
--direction Inbound \
--source-address-prefix AzureLoadBalancer \
--source-port-range "*" \
--destination-address-prefix "*" \
--destination-port-range "*" \
--access AllowThe service tag AzureLoadBalancer matches all traffic from 168.63.129.16 including health probes and diagnostics. Using the service tag is cleaner than hardcoding the IP and future-proofs the rule if Azure adds additional platform IPs.
Azure portal includes a default NSG rule named “AllowAzureLoadBalancerInBound” at priority 65001 in newly created NSGs. If you created the NSG manually or through Terraform without explicitly adding this rule, it will be absent. Always verify this rule exists in backend NSGs.
Cause 2: Application not listening on the probe port
Even with the NSG correctly configured, health probes fail if the application is not listening on the port the probe targets. This happens after deployments where the application crashes on startup, or when the probe port in the load balancer configuration does not match the actual application port.
Verify what the application is listening on from inside the VM:
# On the backend VM (Linux)
sudo ss -tlnp | grep LISTEN
# Expected output for an app on port 8080:
# tcp 0 0 0.0.0.0:8080 0.0.0.0:* LISTEN 12345/nodeIf the port is not in the LISTEN state, the application has crashed or not started. Check application logs:
sudo systemctl status myapp.service
sudo journalctl -u myapp.service -n 50 --no-pagerSimulate the exact HTTP health probe request:
# For an HTTP probe on port 8080 at path /health
curl -v -o /dev/null -w "%{http_code}" http://127.0.0.1:8080/healthThe response code must be exactly 200 for the probe to succeed. If the application returns 301 (redirect to HTTPS), configure the probe to use HTTPS or add a dedicated health endpoint that returns 200 directly without a redirect.
Cause 3: Single backend VM unhealthy — VM stopped or application crashed
If only one VM in the backend pool is unhealthy while others are healthy, the issue is specific to that VM. Check the VM power state first:
az vm get-instance-view \
--resource-group myResourceGroup \
--name myBackendVM2 \
--query "instanceView.statuses[?starts_with(code, 'PowerState/')].displayStatus" \
--output tsvIf the VM shows “VM deallocated” or “VM stopped”, start it:
az vm start \
--resource-group myResourceGroup \
--name myBackendVM2After the VM starts, the load balancer health probe retries automatically within the configured probe interval (default 15 seconds). The backend becomes healthy after the configured number of consecutive successful probes (default 2 probes = 30 seconds minimum wait time).
During a rolling deployment, newly added VMs go through the probe evaluation window before receiving traffic. If your deployment automation adds a VM to the backend pool and immediately routes traffic to it, requests may hit the VM before probes have confirmed it is healthy. Let the probe interval pass before shifting traffic.
Application Gateway unhealthy backends
Application Gateway has a more sophisticated health check than Standard Load Balancer. View the detailed backend health status:
az network application-gateway show-backend-health \
--resource-group myResourceGroup \
--name myAppGateway \
--output jsonThe output shows each backend server with a detailed status message:
{
"backendAddressPools": [
{
"backendHttpSettingsCollection": [
{
"servers": [
{
"address": "10.1.0.4",
"health": "Unhealthy",
"healthProbeLog": "Connect error or unhealthy status code was received",
"ipConfiguration": {}
}
]
}
]
}
]
}Host header problem: Application Gateway health probes include a Host header. By default it is set to the backend IP address. If the application uses virtual hosting and rejects requests where the Host header is an IP address, the probe will get a non-200 response.
Fix by configuring the health probe to send the correct hostname:
az network application-gateway probe create \
--resource-group myResourceGroup \
--gateway-name myAppGateway \
--name myCustomProbe \
--protocol Http \
--host "myapp.example.com" \
--path "/health" \
--interval 30 \
--timeout 30 \
--threshold 3 \
--port 80
az network application-gateway http-settings update \
--resource-group myResourceGroup \
--gateway-name myAppGateway \
--name myHTTPSettings \
--probe myCustomProbeWAF blocking the health probe: If Application Gateway has WAF enabled, the WAF rules may match the probe request and return 403 instead of passing it through. Check the WAF firewall logs in Azure Monitor for blocked requests matching the probe path, then add a WAF exclusion rule for the health probe URI.
Alerting on backend health metrics
Set up a metric alert to detect backend health degradation before users report it:
LB_ID=$(az network lb show \
--resource-group myResourceGroup \
--name myLoadBalancer \
--query id -o tsv)
az monitor metrics alert create \
--name "LBUnhealthyBackendAlert" \
--resource-group myResourceGroup \
--scopes "$LB_ID" \
--condition "avg VipAvailability < 100" \
--window-size 5m \
--evaluation-frequency 1m \
--severity 2 \
--description "Load balancer VIP availability dropped — backend may be unhealthy"The VipAvailability metric drops to 0 when all backends are unhealthy. The DipAvailability metric tracks individual backend health. Use DipAvailability split by BackendIPAddress to identify which specific backend is failing when multiple instances are in the pool.
Common mistakes
- Adding a DenyAll NSG rule without an exception for 168.63.129.16. A hardening practice of blocking all inbound traffic except known sources breaks load balancer health probes if the AzureLoadBalancer service tag is not explicitly allowed at a higher priority. All backends immediately appear unhealthy and no traffic is routed.
- Configuring an HTTP probe when the application returns 301 redirect to HTTPS. HTTP 301 is not 200, so the probe marks the backend as unhealthy. Either configure the probe to use HTTPS, change the probe path to one that returns 200 directly without a redirect, or add a dedicated health endpoint that returns 200 regardless of TLS.
- Assuming Application Gateway probes work the same as Standard Load Balancer probes. Application Gateway probes include a Host header, support custom paths, and have configurable match conditions. Standard Load Balancer probes are simpler TCP or basic HTTP checks. The debugging steps and configuration options differ significantly between the two.
- Not waiting for the probe evaluation window after adding a new backend. A new VM joining a backend pool needs to pass the configured number of consecutive health probes before receiving traffic. If your deployment immediately routes requests to the new VM, users will get errors during the probe evaluation window (at least 2 × probe interval seconds).
Summary
- All load balancer health probes originate from 168.63.129.16 — NSG rules must allow traffic from the
AzureLoadBalancerservice tag on the probe port. - Test the probe from inside the VM using curl or nc to verify the application is listening and returning HTTP 200.
- Application Gateway probes include a Host header — configure a custom probe with the correct hostname if the application uses virtual hosting.
- Use
az network application-gateway show-backend-healthfor detailed per-backend status messages when troubleshooting Application Gateway unhealthy backends.
Frequently asked questions
What IP address do Azure Load Balancer health probes come from?
Azure Load Balancer health probes originate from the IP address 168.63.129.16, which is a virtual IP used by the Azure platform. NSG rules must explicitly allow inbound TCP or HTTP traffic from this IP on the probe port. Blocking this IP causes all backend VMs to appear unhealthy.
Can I test what the health probe sees on my backend VM?
Yes. SSH into the backend VM and run curl -v http://localhost:PORT/PATH for HTTP probes or use nc -zv 127.0.0.1 PORT for TCP probes. This simulates what the probe checks. If curl returns a non-200 response or nc reports connection refused, the application is not responding correctly to probes.
Why does Application Gateway show a backend as unhealthy even though the VM responds to HTTP requests?
Application Gateway health probes send the request with the Host header set to the backend IP address by default. If the application requires a specific hostname in the Host header, it may return a non-200 response. Enable "Pick host name from backend target" in the health probe settings or configure a custom hostname in the probe definition.