Quick Answer
# Find unused EIPs and release them
aws ec2 describe-addresses --query 'Addresses[?AssociationId==`null`].[AllocationId,PublicIp]' --output table
# Release an unused EIP
aws ec2 release-address --allocation-id eipalloc-0abc1234
The Error
Error: creating EC2 EIP: AddressLimitExceeded: The maximum number of addresses has been reached.
status code: 400
Error: creating NAT Gateway: AddressLimitExceeded: The maximum number of addresses has been reached.
What Causes This
AWS limits Elastic IPs to 5 per region by default. Every NAT Gateway, bastion host, and public-facing instance with a static IP consumes one.
Common EIP consumers:
- NAT Gateways — 1 EIP each (multi-AZ = 2-3 EIPs)
- Bastion hosts — 1 EIP each
- Direct-attached public instances — 1 EIP each
- VPN endpoints — 1 EIP each
- Orphaned EIPs — released instances leave EIPs behind
Solution 1: Release Unused Elastic IPs
# List ALL EIPs in the region with association status
aws ec2 describe-addresses \
--query 'Addresses[].{IP:PublicIp,AllocID:AllocationId,AssocID:AssociationId,Instance:InstanceId}' \
--output table
-------------------------------------------------------------------
| DescribeAddresses |
+------------------+------------------+--------+------------------+
| AllocID | AssocID | IP | Instance |
+------------------+------------------+--------+------------------+
| eipalloc-aaa111 | eipassoc-bbb222 | 1.2.3.4| i-0abc123 |
| eipalloc-ccc333 | None | 5.6.7.8| None | ← Unused
| eipalloc-ddd444 | None | 9.0.1.2| None | ← Unused
+------------------+------------------+--------+------------------+
Release the unused ones:
# Release unused EIPs
aws ec2 release-address --allocation-id eipalloc-ccc333
aws ec2 release-address --allocation-id eipalloc-ddd444
Or release ALL unused EIPs:
aws ec2 describe-addresses \
--query 'Addresses[?AssociationId==null].AllocationId' \
--output text | xargs -n1 aws ec2 release-address --allocation-id
Solution 2: Request a Quota Increase
# Check current EIP quota
aws service-quotas get-service-quota \
--service-code ec2 \
--quota-code L-0263D0A3
# Request increase to 20
aws service-quotas request-service-quota-increase \
--service-code ec2 \
--quota-code L-0263D0A3 \
--desired-value 20
Or through the AWS Console: Service Quotas → EC2 → Elastic IP addresses → Request increase
Typical approval: 1-3 business days for moderate increases.
Solution 3: Reduce EIP Usage
Use Single NAT Gateway (Non-Production)
# Instead of 3 NAT Gateways (3 EIPs):
resource "aws_nat_gateway" "single" {
allocation_id = aws_eip.nat.id
subnet_id = aws_subnet.public[0].id
}
resource "aws_eip" "nat" {
domain = "vpc"
}
# Route all private subnets through one NAT
resource "aws_route" "private" {
count = length(aws_subnet.private)
route_table_id = aws_route_table.private[count.index].id
destination_cidr_block = "0.0.0.0/0"
nat_gateway_id = aws_nat_gateway.single.id
}
One NAT Gateway instead of three saves 2 EIPs + ~$65/month.
Use ALB Instead of Per-Instance EIPs
# Instead of EIP per instance, put them behind an ALB
resource "aws_lb" "web" {
name = "web-alb"
load_balancer_type = "application"
subnets = aws_subnet.public[*].id
}
# Instances in private subnets — no EIPs needed
resource "aws_instance" "web" {
count = 3
subnet_id = aws_subnet.private[count.index % length(aws_subnet.private)].id
# No EIP needed
}
Use SSM Instead of Bastion + EIP
# No bastion host needed — connect via SSM Session Manager
resource "aws_iam_instance_profile" "ssm" {
role = aws_iam_role.ssm.name
}
resource "aws_instance" "web" {
iam_instance_profile = aws_iam_instance_profile.ssm.name
# No EIP, no public subnet needed
}
aws ssm start-session --target i-0abc123
Solution 4: Audit EIP Usage Across Regions
# Check all regions
for region in us-east-1 us-west-2 eu-west-1 ap-southeast-1; do
count=$(aws ec2 describe-addresses --region $region --query 'length(Addresses)')
echo "$region: $count EIPs"
done
Solution 5: Manage EIPs in Terraform
Track EIPs to prevent orphaning:
resource "aws_eip" "nat" {
count = var.az_count
domain = "vpc"
tags = {
Name = "nat-${count.index}"
}
lifecycle {
# Prevent accidental EIP release (keeps your static IP)
prevent_destroy = true
}
}
Hands-On Courses
- Terraform for Beginners on CopyPasteLearn
- Terraform By Example — practical code examples
Conclusion
AWS limits Elastic IPs to 5 per region. Release unused EIPs first (aws ec2 describe-addresses to find them), then reduce consumption: use a single NAT Gateway for non-production, ALB instead of per-instance EIPs, and SSM instead of bastion hosts. Request a quota increase if you genuinely need more.
