Back to blog
AzureBest PracticesCloud SecurityNetworkingReliability

Azure Load Balancer Has No Backend Instances: Why It Happens and How to Fix It

An Azure Load Balancer with an empty backend pool means traffic goes nowhere. Learn why it happens, the risks, and step-by-step CLI and Terraform fixes.

TL;DR

This check flags Azure Load Balancers whose backend pool has zero registered instances, meaning traffic hitting the load balancer goes nowhere. Add healthy VMs, scale set instances, or NICs to the backend pool, or remove the orphaned load balancer if it is no longer needed.

An Azure Load Balancer with an empty backend pool is the networking equivalent of a front door that opens onto a brick wall. The frontend IP is live, listening rules are configured, health probes are running, but there is nothing behind it to actually serve requests. Lensix raises lb_noinstances when it finds a backend pool with no registered targets so you can either wire it up or clean it up.

This is one of those findings that rarely shows up as a CVE or an alarming red banner, but it has a habit of surfacing during incidents, cost reviews, and audits. Let us walk through what it means, why it bites people, and how to deal with it properly.


What this check detects

The check inspects each Azure Load Balancer in your subscription and examines its backend address pools. If a backend pool exists but contains no associated network interfaces, virtual machines, or virtual machine scale set instances, the load balancer has nothing to distribute traffic to. Lensix flags this configuration.

In Azure terms, a load balancer distributes inbound flows across a backend pool. That pool can be populated in a few ways:

  • Direct NIC association from individual virtual machines
  • Membership through a virtual machine scale set
  • IP-based backend pool members (for certain Standard SKU scenarios)

When none of these are present, the load balancing rules have no destination. Health probes have nothing to probe. The resource is effectively inert.

Note: An empty backend pool is not the same as a backend pool full of unhealthy instances. This check specifically catches pools with zero members. A separate problem, all members failing health probes, would produce different symptoms but a similar end result for clients.


Why it matters

An empty backend pool tends to mean one of three things, and each carries its own risk.

1. A live service is silently broken

If this load balancer is meant to be serving production traffic, an empty pool means total outage for whatever sits behind it. Clients connecting to the frontend IP will see connection resets or timeouts depending on the rule configuration. This is the worst case, and it often happens after a botched deployment where old instances were torn down before new ones were attached, or where an autoscaling event drained the pool to zero.

2. An orphaned resource is costing money and widening your attack surface

Standard SKU load balancers carry an hourly charge plus data processing costs regardless of whether they serve any traffic. An empty load balancer that nobody remembers creating is pure waste. Worse, it usually comes with a public frontend IP, an NSG, and inbound rules that still exist in your environment. That is an entry point sitting in your network diagram that nobody is monitoring.

3. Configuration drift is hiding a deeper problem

Empty pools frequently signal that your infrastructure-as-code and your running state have diverged. Maybe a Terraform apply partially failed. Maybe someone deleted a scale set in the portal without removing its load balancer. Drift like this erodes trust in your IaC and makes the next change riskier.

Warning: Standard Load Balancers bill per hour and per processed gigabyte. An idle one with a public IP can quietly add up across dozens of subscriptions. Always confirm whether a flagged load balancer is genuinely orphaned before assuming it is harmless.


How to fix it

Start by deciding the load balancer's fate. Is it supposed to have instances behind it, or should it not exist at all? Investigate before you touch anything.

Step 1: Inspect the load balancer and its backend pools

az network lb show \
  --resource-group myResourceGroup \
  --name myLoadBalancer \
  --query "{name:name, sku:sku.name, backendPools:backendAddressPools[].name}" \
  -o json

Then list the backend pool members to confirm the pool is genuinely empty:

az network lb address-pool show \
  --resource-group myResourceGroup \
  --lb-name myLoadBalancer \
  --name myBackendPool \
  --query "{name:name, backendIpConfigurations:backendIPConfigurations, loadBalancerBackendAddresses:loadBalancerBackendAddresses}" \
  -o json

If both backendIPConfigurations and loadBalancerBackendAddresses come back null or empty, the pool has no members.

Step 2a: Attach instances (if the load balancer should be in use)

For a virtual machine, you associate its NIC IP configuration with the backend pool:

az network nic ip-config address-pool add \
  --resource-group myResourceGroup \
  --nic-name myVmNic \
  --ip-config-name ipconfig1 \
  --lb-name myLoadBalancer \
  --address-pool myBackendPool

For a virtual machine scale set, set the backend pool at the scale set level so new instances join automatically:

az vmss update \
  --resource-group myResourceGroup \
  --name myScaleSet \
  --add virtualMachineProfile.networkProfile.networkInterfaceConfigurations[0].ipConfigurations[0].loadBalancerBackendAddressPools \
  "{'id':'/subscriptions//resourceGroups/myResourceGroup/providers/Microsoft.Network/loadBalancers/myLoadBalancer/backendAddressPools/myBackendPool'}"

az vmss update-instances \
  --resource-group myResourceGroup \
  --name myScaleSet \
  --instance-ids "*"

After attaching instances, confirm your health probe matches a real listening endpoint. A correctly populated pool with a misconfigured probe will still mark everything unhealthy.

Step 2b: Delete the load balancer (if it is orphaned)

Danger: Deleting a load balancer is irreversible and will break any client still pointed at its frontend IP. Confirm there is no DNS record, no application gateway backend, and no documented dependency before running this. Check flow logs or NSG logs for recent inbound traffic first.

az network lb delete \
  --resource-group myResourceGroup \
  --name myLoadBalancer

Do not forget the associated public IP, which is billed separately and is not removed with the load balancer:

az network public-ip delete \
  --resource-group myResourceGroup \
  --name myLoadBalancerPublicIp

Step 3: Fix it in your IaC, not just in the live environment

If you fix this only through the CLI or portal, your next deployment will recreate the drift. Reflect the change in Terraform, Bicep, or whatever you use. Here is a Terraform example that wires a scale set into a backend pool correctly:

resource "azurerm_lb_backend_address_pool" "web" {
  name            = "web-backend-pool"
  loadbalancer_id = azurerm_lb.web.id
}

resource "azurerm_linux_virtual_machine_scale_set" "web" {
  name                = "web-vmss"
  resource_group_name = azurerm_resource_group.main.name
  location            = azurerm_resource_group.main.location
  sku                 = "Standard_B2s"
  instances           = 2

  network_interface {
    name    = "web-nic"
    primary = true

    ip_configuration {
      name                                   = "internal"
      primary                                = true
      subnet_id                              = azurerm_subnet.web.id
      load_balancer_backend_address_pool_ids = [azurerm_lb_backend_address_pool.web.id]
    }
  }
}

How to prevent it from happening again

Empty backend pools are almost always a process failure rather than a one-off mistake. Close the gap with automation.

Use Azure Policy to flag the condition

While Azure Policy cannot directly count backend pool members in a built-in definition, you can pair it with a periodic check. A practical approach is to run a scheduled query against Azure Resource Graph:

az graph query -q "
resources
| where type == 'microsoft.network/loadbalancers'
| extend pools = properties.backendAddressPools
| mv-expand pools
| extend memberCount = array_length(pools.properties.backendIPConfigurations)
| where isnull(memberCount) or memberCount == 0
| project name, resourceGroup, subscriptionId, poolName = pools.name
"

Wire that into a scheduled function or pipeline and alert when results are non-empty.

Tip: Lensix runs this exact class of check continuously across your subscriptions, so you get the finding without maintaining your own Resource Graph queries or cron jobs. Use the manual query above for ad hoc spot checks and let the platform handle ongoing coverage.

Gate it in CI/CD

Add a deployment-time validation step that fails the pipeline if a load balancer is created without a corresponding backend pool association. For Terraform, a simple terraform plan review combined with a policy-as-code tool like Conftest or OPA can catch a backend pool resource that has no instance referencing it.

Order your deployments correctly

Many empty-pool outages come from teardown ordering during blue-green or rolling deploys. Make sure new instances are registered and passing health probes before old ones are removed. If you use scale sets, this is handled for you, which is one more reason to prefer them over manually managed VM pools behind a load balancer.


Best practices

  • Prefer scale sets for backend pools. Membership is managed automatically, so scaling events never leave you with an empty pool.
  • Tag every load balancer with an owner and purpose. When a finding appears, you know immediately whether it is orphaned or load-bearing.
  • Always configure a meaningful health probe. A populated pool is only useful if the probe targets a real application endpoint, not just an open port.
  • Clean up the whole chain. When you retire a load balancer, also remove its public IP, NSG rules, and DNS records. Leftover public IPs are a common source of dangling DNS and subdomain takeover risk.
  • Reconcile drift regularly. Run terraform plan on a schedule and treat unexpected diffs as incidents, not noise.

An empty backend pool is usually quick to fix, but the value is in catching it early. Whether it is an outage waiting to be noticed or an abandoned resource quietly billing you, surfacing it before your customers or your finance team do is the whole point.

Azure Load Balancer Empty Backend Pool Fix | Lensix | Lensix