Unattached Elastic IPs: the basics
Why a public IP you allocated and forgot keeps billing
An Elastic IP (EIP) is a static public IPv4 address you allocate to your account and then associate with a running instance or network interface. AWS has always charged for an EIP that is allocated but not doing useful work — specifically when it is not associated with a running instance, when it's associated with a stopped instance, or when it sits on a network interface that isn't attached to anything. That idle charge is roughly $0.005 per hour, about $3.65 per month, per address.
Since February 1, 2024 the picture got broader: AWS now charges $0.005/hour for every public IPv4 address in your account — including ones actively associated with running instances — because IPv4 is a scarce, paid resource. So the EIP on your healthy web server now costs the same $3.65/month as the orphaned one. This lesson is about the orphans specifically: addresses you're paying for that aren't earning anything, because they're the pure-waste subset that's safe to reclaim.
EIPs get flagged because the asymmetry catches people out. An address is small, invisible in most consoles, and survives the thing it was attached to. Terminate an instance and its EIP is automatically disassociated but stays allocated to your account — still billing — until someone explicitly releases it. One stranded EIP is a rounding error; three hundred of them across a long-lived organisation is a real, recurring line item with nothing on the other side of it.
In this lesson you'll learn the two billing mechanics at play — the long-standing idle-EIP charge and the universal IPv4 charge introduced in February 2024 — and how addresses get stranded after an instance is terminated, stopped, or detached. You'll see the AWS CLI commands to find every unassociated EIP and release it, the small-per-resource / large-in-aggregate pattern that makes this worth a cadence, the IPv6 migration angle as the long-term fix, and the one real risk: releasing an address that something off-platform still points at — a customer firewall allowlist, a DNS A record, or a BYOIP block.
The day every IPv4 address got a price tag
Before February 1, 2024, AWS only charged for idle Elastic IPs — an address attached to a running instance was free. Then AWS started charging $0.005/hour for every public IPv4 address in every account, in-use or not, citing a 300%+ rise in the cost of acquiring IPv4 blocks over the prior five years. Overnight, organisations with tens of thousands of public IPs saw a brand-new five- and six-figure annual line item appear with zero change to their architecture. It turned a long-ignored cleanup task — releasing stranded addresses — into something with a visible, immediate payback, and quietly made IPv6 a budget conversation rather than a purely technical one.
Reclaiming stranded Elastic IPs in action
Dani runs the monthly FinOps cadence at a logistics company with about 30 AWS accounts. The dashboard flags 47 Elastic IPs that are allocated but associated with nothing — roughly $172 a month, and the count has crept up steadily since the IPv4 charge landed. Most trace back to instances that were terminated months ago; the addresses just never got handed back.
Dani doesn't release them blind. The real risk isn't anything inside AWS — a stranded EIP breaks nothing by definition. The risk is something outside AWS still pointing at the address: a customer's firewall allowlist pinned to a specific IP, a DNS A record nobody updated, or a partner integration that whitelisted the address years ago. So before releasing each one, Dani checks Route 53 and the team's runbooks for any reference to the address.
Two of the 47 turn out to be live: one is a static egress IP a payments partner has allowlisted, the other is in a DNS A record for a legacy admin endpoint. Those get tagged Lifecycle=pinned and left alone. The remaining 45 have no references anywhere — terminated instances, an old NAT that was replaced, a detached ENI from a deleted load balancer. Dani releases all 45 in one scripted pass: about $164/month reclaimed, total elapsed time under fifteen minutes.
First, list every Elastic IP in the account that is not associated with anything. An EIP with a null AssociationId is allocated, billing, and attached to nothing.
Every address with a null AssociationId is allocated, unattached, and costing ~$3.65/month.
Once you've confirmed nothing off-platform references the address (no DNS A record, no firewall allowlist, not a BYOIP block someone depends on), release it by allocation ID.
Release is instant and irreversible — the address goes back to AWS's pool and is almost certainly gone for good.
Elastic IP billing under the hooddeep dive
There are two separate meters. The long-standing one charges $0.005/hour (~$3.65/month) for an Elastic IP that is not associated with a running instance — i.e. allocated but idle, associated with a stopped instance, or sitting on an unattached network interface. The second, live since February 1, 2024, charges the same $0.005/hour for every public IPv4 address in the account regardless of state, including EIPs and auto-assigned public IPs on running instances. The first is the waste subset you can reclaim by releasing; the second is the cost of using IPv4 at all, which you reduce by using fewer public addresses (or migrating to IPv6).
The key state field is AssociationId. An EIP returned by describe-addresses with a null AssociationId is attached to nothing — that's the unambiguous orphan. An EIP with a non-null AssociationId but a NetworkInterfaceId whose ENI is itself detached (status available rather than in-use) is a subtler case: it's technically associated, but to a dead interface, and still on the idle meter. Terminating an instance auto-disassociates its EIP but never releases it — the allocation persists in your account until an explicit release-address call.
Releasing is irreversible in practice. The address returns to AWS's regional pool and is recycled to other customers; you will almost never get the same IP back. That's precisely why the only real risk here lives outside AWS: anything that hardcoded the address — a customer's firewall allowlist, a third-party API whitelist, a DNS A record, a BYOIP arrangement — will silently break, and you can't undo it. The CLI gives you nothing to confirm those references; that check is a runbook and DNS step, not an API call.
# Find unassociated EIPs, then check Route 53 for any A record pointing at each
# address BEFORE releasing. The DNS check is the safety gate, not the API call.
for alloc in $(aws ec2 describe-addresses \
--query "Addresses[?AssociationId==null].AllocationId" --output text); do
ip=$(aws ec2 describe-addresses --allocation-ids "$alloc" \
--query 'Addresses[0].PublicIp' --output text)
echo "== $alloc -> $ip =="
# Scan every hosted zone for an A record resolving to this IP.
for zone in $(aws route53 list-hosted-zones --query 'HostedZones[].Id' --output text); do
aws route53 list-resource-record-sets --hosted-zone-id "$zone" \
--query "ResourceRecordSets[?Type=='A' && contains(ResourceRecords[].Value, '$ip')].Name" \
--output text
done
done
# Only release allocations that printed no DNS hits AND clear the firewall/allowlist review. What is the impact of unattached Elastic IPs?
The direct cost is small per address and material in aggregate. One stranded EIP is ~$3.65/month — genuinely a rounding error. But this is a category that scales with sprawl: 50 orphans is ~$180/month, 300 is ~$1,100/month, and a large multi-account organisation that's been running since before anyone cared about IPv4 charges routinely carries well into four figures a month of addresses attached to nothing. The meter runs every hour regardless, and unlike compute there's no usage variable — it's a flat fee for an idle resource.
The 2024 universal IPv4 charge changed the economics of the whole category, not just the orphans. Before then, only idle EIPs cost money, so cleanup had a tiny payback and rarely made anyone's list. Now every public address in the fleet is metered, which means the in-use addresses you can't simply release become a standing cost that only architecture — fewer public IPs, NAT consolidation, IPv6 — can reduce. The orphan cleanup is the easy, immediate win; the larger structural cost is the conversation it should prompt.
There's a hidden-resource angle too. Orphaned EIPs hide on detached ENIs left behind by deleted load balancers, terminated instances, and replaced NAT Gateways — places nobody looks. Without tagging, it's hard to tell which addresses are deliberately pinned (a static egress IP a partner allowlisted, a DNS-fronted endpoint) and which are pure debris. That ambiguity is exactly what makes people leave the whole category alone, which is how it grows.
Finally, a stranded public IP is a small attack-surface and audit item, not just a cost one. An address that still resolves in DNS but points at nothing, or one a partner still allowlists but you've forgotten about, is the kind of loose end that surfaces in a security review. Reclaiming orphans tightens the surface as much as it trims the bill — the cost report is just the easiest place to see the mess.
How do you release unattached Elastic IPs safely?
Cleanup is a four-step loop: inventory every unassociated address, confirm nothing off-platform references it, release the clear ones, and adopt conventions (plus IPv6 where you can) so the orphans don't come back.
1. Inventory every unassociated address across regions and accounts
Run describe-addresses in every region and account and filter to AssociationId == null. Capture the public IP, allocation ID, any Name/owner tag, and whether it sits on a detached ENI. Also watch the subtler case: an EIP associated with a network interface whose ENI is available (detached) rather than in-use — still idle, still billing. Anything with no tag and no association is a candidate.
2. Check for off-platform references before touching anything
This is the whole risk and it lives outside AWS. For each candidate address, confirm there is no DNS A record pointing at it (scan your Route 53 zones and any external DNS), no customer or partner firewall allowlist pinned to it, and that it isn't part of a BYOIP block someone depends on. Release is irreversible — you won't get the same IP back — so a hardcoded allowlist or stale DNS record is the one thing that turns a safe cleanup into an outage. When in doubt, tag Lifecycle=pinned and leave it.
3. Release the confirmed orphans by allocation ID
For addresses that cleared the reference check, call release-address --allocation-id eipalloc-.... There's no snapshot or undo here as there is with storage — the safety net is entirely the step-2 check, so don't skip it. Batch the releases in a single scripted pass and log each one (IP, allocation ID, date, who approved) so there's a record if a forgotten dependency surfaces weeks later.
4. Prevent recurrence with conventions and IPv6
Make releasing an address part of the same change that decommissions the resource it served — a decommission checklist or an AWS Config rule that flags long-lived unassociated EIPs. Tag deliberately-kept addresses Lifecycle=pinned with an owner so the next audit is short. The structural long-term fix is IPv6: addresses in the IPv6 space aren't metered the way scarce IPv4 is, so migrating public-facing and egress paths to IPv6 shrinks the whole category, not just the orphans.
# Inventory unassociated EIPs, then release only the ones you've cleared.
# RUN THE DNS / ALLOWLIST CHECK FIRST — release-address is irreversible.
REGION=us-east-1
aws ec2 describe-addresses --region $REGION \
--query "Addresses[?AssociationId==null].[AllocationId,PublicIp]" --output text
# After confirming no DNS A record and no firewall allowlist references each IP:
for alloc in eipalloc-0aa11bb22cc33dd eipalloc-0bb22cc33dd44ee; do
echo "Releasing $alloc"
aws ec2 release-address --region $REGION --allocation-id "$alloc"
done Quick quiz
Question 1 of 5You find an Elastic IP with a null AssociationId that's been billing for months. Before you run release-address, what's the single most important thing to confirm?
You scored
0 / 5
Keep learning
Dig deeper into Elastic IP mechanics, the 2024 IPv4 pricing change, and the IPv6 path that shrinks the whole category.
- Elastic IP addresses — Amazon EC2 User Guide Authoritative reference on allocating, associating, disassociating, and releasing Elastic IP addresses.
- New — AWS Public IPv4 Address Charge AWS announcement of the February 2024 universal $0.005/hour charge on all public IPv4 addresses, plus Public IP Insights.
- Amazon VPC pricing — public IPv4 addresses Current per-hour rates for Elastic IPs and public IPv4 addresses — the numbers behind the cleanup math.
- FinOps Foundation — Cloud Rate and Usage Optimization How resource-cleanup discipline and IPv6 adoption fit the broader FinOps lifecycle and operating model.
You've completed Release unattached Elastic IPs. You now know the two billing meters — the long-standing idle-EIP charge and the universal IPv4 charge from February 2024 — how addresses get stranded after a resource is deleted, the inventory-check-release loop, and the one real risk: an off-platform allowlist or DNS record pinned to an address you're about to give back. Next time the wastage report flags an unattached EIP, you'll have a defensible path from "flagged" to "released" in minutes.
Back to the library