Skip to main content
emnode
Cost

Remove application gateways with empty backend pools

An Azure Application Gateway with no backend targets routes nothing, returns a bad gateway error to anyone who hits it, and still bills the full fixed gateway-hour cost every hour it stays provisioned. This lesson finds those idle gateways across a subscription and decides, gateway by gateway, whether to stop, delete or reconnect them.

13 min·10 sections·AZURE

Last reviewed

Idle application gateways: the basics

What does an application gateway with an empty backend pool actually cost?

An Azure Application Gateway is a layer 7 load balancer, and it is one of the more expensive standing resources you can leave running. Its v2 billing has two parts: a fixed gateway-hour cost that you pay for every hour the gateway is provisioned and available, regardless of how many instances run or how much traffic flows, and a capacity unit cost that scales with the work it actually does. An idle gateway, one with no backend targets, still pays the fixed part in full. It is parked compute with nothing plugged into it.

A gateway is idle when its backend address pools are empty: no virtual machines, no scale set, no app service, no IP addresses to forward requests to. The Cost Optimization workbook in Azure Advisor flags exactly this on its Networking tab, under 'Application Gateway with empty backend pool', and the rule it applies is blunt: an app gateway is considered idle if there is not any backend pool with targets. With nothing behind it, the gateway cannot route a single request. Anyone who reaches its listener gets a 502 Bad Gateway, so it is not even quietly serving something forgotten, it is serving errors while it bills.

Most of these are leftovers, not live services. A gateway spun up for a migration that finished, a proof of concept that was never torn down, an environment whose backend was deleted but whose front door was not. The work is to list every gateway whose pools are empty, separate the genuinely abandoned ones from the few that are mid-deployment or deliberately parked, then stop or delete the dead weight and reconnect anything that should have a backend.

In this lesson you will learn how Azure Application Gateway billing works, why an empty backend pool means a gateway is pure waste, how to find every idle gateway across a subscription, and how to decide for each one whether to stop it, delete it or reconnect a backend. The grounding is the Cost Optimization workbook's Networking tab check, 'Application Gateway with empty backend pool', which considers a gateway idle when no backend pool has targets.

Fun fact

The gateway that served only errors

An application gateway with an empty backend pool does not fail silently. Because it has no targets to route to, every request that reaches its listener gets back a 502 Bad Gateway, which is the same error Azure documents for a gateway whose backend has no healthy members. So an idle gateway is doubly pointless: it bills the full fixed hourly rate and the only thing it can return to a visitor is an error page. If one of these is sitting behind a DNS record someone forgot, the most likely way you find out is a monitoring alert or a confused user, not the bill, which is exactly why these survive for months.

Finding idle gateways across a subscription

Priya runs the platform team at a company that has been on Azure for four years and has accumulated resources across a dozen resource groups. A quarterly cost review highlights application gateway spend that nobody can fully account for, and the Cost Optimization workbook's Networking tab shows several gateways flagged with empty backend pools.

Rather than open each gateway in the portal, Priya queries the whole subscription at once to list every gateway whose backend pools have no addresses, so the genuinely idle ones can be separated from anything mid-deployment before anything is stopped.

List every application gateway whose backend pools contain no backend addresses. These are the idle gateways billing for nothing.

$ az network application-gateway list --query "[?length(backendAddressPools[?length(backendAddresses)>`0`])==`0`].{name:name, sku:sku.name, state:operationalState}" -o table
Name Sku State
------------------- ------------- --------
agw-migration-old Standard_v2 Running
agw-waf-poc WAF_v2 Running
agw-newenv-staging Standard_v2 Running
# Three gateways with empty pools. The WAF_v2 one bills the highest fixed rate.

Every gateway listed here routes nothing and bills the full fixed gateway-hour cost. The WAF_v2 SKU carries a higher fixed rate than Standard_v2, so it is the highest-value target. Check the staging one is not mid-deployment before acting.

How an application gateway becomes idle and why it still billsdeep dive

An application gateway routes traffic by matching an incoming request to a listener, applying its routing rules, and forwarding to a backend address pool. The backend pool is the list of targets: virtual machines, a scale set, an app service, or raw IP addresses and FQDNs. When that pool is empty, the gateway has nowhere to send the request, so it cannot serve anything and returns a 502. The Cost Optimization workbook uses precisely this signal: it inspects each gateway's backend address pools and treats the gateway as idle when none of them has targets.

Billing does not depend on whether the gateway is useful, only on whether it is provisioned. For the v2 SKUs, Microsoft documents the fixed cost as based on the time the gateway is provisioned and available for processing requests, charged even if zero instances are reserved via a minimum instance count of zero. In other words, an empty-pool gateway that handles no traffic at all still pays the fixed gateway-hour cost for every hour it exists. A partial hour is billed as a full hour. The capacity unit cost, the variable part, is near zero for an idle gateway because there is no traffic, but the fixed part is unavoidable while the gateway is running.

There are two distinct levers for stopping the charge. Stopping the gateway with az network application-gateway stop halts billing, and Microsoft is explicit that when you stop and start an application gateway, billing also stops and starts. That preserves the configuration if you might need the gateway back. Deleting it with az network application-gateway delete removes the resource entirely, which is the right call when the gateway is genuinely abandoned. Note that any PUT operation against a stopped gateway, even adding a tag, restarts it and resumes billing, so a stopped gateway is a holding state, not a permanent free park.

What is the impact of leaving idle gateways running?

The direct impact is a recurring charge for nothing. Each idle gateway pays its full fixed gateway-hour cost every hour, every day, with no service delivered in return. Individually a single gateway is easy to overlook against a large bill, but the charge is relentless: it reappears every month until someone acts, and across a multi-subscription estate the idle gateways add up to a number worth recovering.

The second-order impact is that idle gateways are a symptom of a lifecycle gap. A gateway with an empty pool almost always means a teardown step was skipped: a migration completed, a proof of concept ended, an environment was decommissioned but its front door survived. Where you find one, you usually find others, and the same gap will keep producing them unless the sweep becomes routine. There is also a small operational hazard: an idle gateway behind a live DNS record serves 502 errors to anyone who reaches it, which can look like an outage and waste investigation time.

Unlike most cost optimisation, there is no trade-off to weigh here. Right-sizing a database or a VM means balancing cost against performance and risk. An empty-pool gateway has no performance to protect and no workload to risk, so removing it is a pure saving. The only care required is confirming the pool is empty because the gateway is finished with, not because a backend is still being wired up.

How do you clear idle gateways safely?

Work the whole subscription at once rather than gateway by gateway. The order matters: confirm a pool is empty because the gateway is finished with, not because a backend is mid-build, before you stop or delete anything.

1. Inventory every gateway by backend state

List every application gateway whose backend address pools contain no addresses, across all resource groups in the subscription. Treat this list as the source of truth. Capture the SKU and operational state for each, because the SKU sets the fixed rate you will recover and the state tells you whether it is already stopped.

2. Separate abandoned gateways from mid-deployment ones

An empty pool usually means abandoned, but not always. A gateway provisioned ahead of a backend that is still being wired up will also show empty. For each one, confirm with the owning team or via tags and recent activity whether the gateway is finished with or in flight. Only the genuinely abandoned ones are safe to remove.

3. Stop or delete, highest fixed rate first

For abandoned gateways you might want back, stop them: billing halts immediately and the configuration is preserved. For gateways that are genuinely finished with, delete them outright. Prioritise the WAF_v2 gateways, which carry the higher fixed rate, then the Standard_v2 ones. Each action takes effect immediately and recovers the full fixed cost.

4. Reconnect anything that should have a backend, then make the sweep routine

If a gateway is meant to be live but lost its pool, reconnect a real backend, for example by populating one of its backend address pools with target servers, rather than leaving it idle. Then schedule the empty-pool query against every subscription so any future gateway that loses its backend is flagged within days, not at the next audit.

# 1. Find every application gateway in the subscription with no backend targets.
#    A gateway is idle when no backend address pool contains any addresses.
az network application-gateway list \
  --query "[?length(backendAddressPools[?length(backendAddresses)>\`0\`])==\`0\`].{name:name, rg:resourceGroup, sku:sku.name, state:operationalState}" \
  -o table

# 2. For an abandoned gateway you might want back: stop it (billing halts immediately).
az network application-gateway stop \
  --resource-group rg-network \
  --name agw-migration-old

# 3. For a gateway that is genuinely finished with: delete it outright.
az network application-gateway delete \
  --resource-group rg-network \
  --name agw-waf-poc

# 4. If a gateway SHOULD be live but lost its pool, reconnect a real backend
#    by populating one of its backend address pools with target servers.
#    --servers takes a space-separated list of backend FQDNs or IP addresses.
az network application-gateway address-pool update \
  --resource-group rg-network \
  --gateway-name agw-newenv-staging \
  --name appGatewayBackendPool \
  --servers app-backend.internal.example.com

Quick quiz

Question 1 of 5

The Cost Optimization workbook flags an application gateway under 'Application Gateway with empty backend pool'. What does that tell you about the gateway?

You can now treat idle application gateways as one routine sweep rather than an audit surprise: list every gateway whose backend pools are empty across the subscription, separate the abandoned ones from anything mid-deployment, stop or delete the dead weight highest-fixed-rate first, reconnect anything that should be live, and schedule the query so future idle gateways are caught within days.

Back to the library