Unused Elastic IP cost has been the rule rather than the exception since 2024-02-01: AWS charges every public IPv4 address per hour, associated or not; Azure charges every Standard address whether it hangs on a resource or not; Google Cloud charges reserved external addresses even when no instance uses them. The saving comes from an address without a resource having no purpose and being released at once, and from addresses handed out by habit being replaced by private subnets, load balancers and IPv6. The fix belongs to the team that maintains the network templates, with a list per account that the cloud owner works through.
Symptom
The bill carries addresses as lines of their own. On AWS these are lineItem/UsageType EUC1-PublicIPv4:IdleAddress for an address without a resource and EUC1-PublicIPv4:InUseAddress for an associated one, both under AmazonVPC, per hour; the hours per account divided by 720 is the number of addresses. On Azure they sit under MeterCategory Virtual Network with MeterSubCategory IP Addresses and a MeterName such as Standard IPv4 Static Public IP, per hour. On Google Cloud Compute Engine carries the SKUs Static Ip Charge for reserved, unassigned addresses and External IP Charge for addresses on running instances. What addresses cost at the three providers and how they belong to load balancers and NAT is in load balancers, NAT and public IPs; this page covers the addresses nobody uses.
How to detect it
AWS
The Elastic IP addresses without an association, and the instances with an automatically assigned public address:
aws ec2 describe-addresses --query 'Addresses[?AssociationId==null].[PublicIp,AllocationId,Domain,Tags[?Key==`Name`].Value|[0]]' --output table
aws ec2 describe-instances --query 'Reservations[].Instances[?PublicIpAddress!=null].[InstanceId,PublicIpAddress,State.Name,SubnetId]' --output table
AWS charges all Elastic IP addresses, in use or unassociated, and all public IPv4 addresses of running instances; the VPC price in US East (Ohio) is USD 0.005 per address and hour (read on 2026-10-21, Elastic IP addresses, VPC pricing). Trusted Advisor flags under "Unassociated Elastic IP Addresses" every address not associated with a running instance. Public IP Insights in IPAM shows every public IPv4 address of an account by type and use, at no extra cost for that view. In billing data the IdleAddress line per account is the figure, and the InUseAddress line the list of addresses that are an architecture question (AWS Cost and Usage Report).
Azure
The public addresses without an IP configuration and without a NAT gateway:
az network public-ip list --query "[?ipConfiguration==null && natGateway==null].{name:name, ip:ipAddress, sku:sku.name, alloc:publicIPAllocationMethod, rg:resourceGroup}" -o table
Public IPv4 addresses carry a charge, IPv6 addresses do not; Basic addresses were retired on 2025-09-30, and Standard addresses are always static, so they survive the deletion of the VM (public IP addresses). Azure Advisor carries no recommendation on unassociated addresses on the read date; its recommendation on network gateways without connections names their addresses with them. In the cost export the candidate is a publicIPAddresses/ resource with a full hourly meter whose name hangs on no network interface, load balancer or gateway (Azure cost exports).
Google Cloud
The reserved addresses with status and users:
gcloud compute addresses list --format="table(name,region.basename(),address,addressType,status,users.list(),creationTimestamp)"
An address with status RESERVED and an empty users field is reserved and unused. The idle IP address recommender, google.compute.address.IdleResourceRecommender, returns the same list with a cost estimate (Recommenders):
gcloud recommender recommendations list --project=<project-id> --location=<region> \
--recommender=google.compute.address.IdleResourceRecommender --format="table(name.basename(),description,stateInfo.state)"
In the billing export the candidate is a Static Ip Charge line per project; the prices per address and hour are on the network price list (Google Cloud billing export).
How to fix it
- Go through the list per account, subscription or project with the owner; an address with a DNS record or an allow list at a customer stays until the record is changed, everything else is released.
- Release. AWS:
aws ec2 release-address --allocation-id eipalloc-0123456789abcdef0 --dry-run, then without--dry-run; an address on a stopped instance is detached first withaws ec2 disassociate-address --association-id <id>. Azure:az network public-ip delete --name <ip> --resource-group <rg>, without a dry run, so only against the checked list. Google Cloud:gcloud compute addresses delete <address> --region=<region>. - Lower the need where addresses are in use but not needed: instances into private subnets behind a load balancer or a NAT gateway, one address per load balancer instead of per instance, bastion hosts replaced by Session Manager, Azure Bastion or Identity-Aware Proxy, and IPv6, which comes without the IPv4 charge at all three, wherever the other side speaks it.
- Correct the template:
MapPublicIpOnLaunchset tofalsein private subnets, no public address in the VM template on Azure,--no-addresson Google Cloud, and a check in the review that justifies every new public address (cost in the development lifecycle).
The hourly charge ends with the release; the daily export shows it the next day.
Risks and side effects
- A released address does not come back: on AWS it can sometimes be recovered after the release with
allocate-address --addressas long as nobody else has received it, on Azure and Google Cloud not at all. DNS records, firewall rules at customers and partners, SPF records and licences bound to the address come before the release. - An unassociated address is sometimes deliberate: the reserved address of a failover plan or a maintenance window. The tag says so, and such an address gets an expiry date.
- Moving an instance into a private subnet needs a way out, a NAT gateway or an endpoint, which costs per hour itself; idle NAT gateways and endpoints describes the counter-calculation.
- IPv6 helps only where clients and services speak it; a dual-stack load balancer keeps its IPv4 address and its charge.
- On Azure a VM with a dynamic Basic address loses it on deallocation; Standard addresses are static and do not change, which is why they are left over when the VM is deleted.
How to verify the saving
Before: per account, the IdleAddress hours, the IP Addresses meters and the Static Ip Charge line in the last full month, and from them the number of addresses. After: the same lines in the first full month after the release, expected zero for unassociated addresses and, after step 3, a lower number of InUseAddress hours. The number of addresses times the hourly charge times 720 is the estimate, the team's release makes it accepted, the deletion implemented, and the following month's invoice realises it in the pattern of estimated, accepted, implemented, verified. The number of addresses without a resource is the figure that then sits at zero in the cost review.
Sources
Read on 2026-10-21. Elastic IP addresses, Amazon VPC pricing, Trusted Advisor cost optimization checks, describe-addresses, Public IP addresses in Azure, Azure Advisor cost recommendations, Reserve a static external IP address, Google Cloud network pricing, Recommenders.