Why your VPC peering connection fails silently (and how to catch it before deploy)
Your VPC peering connection says Active, but traffic times out with no error anywhere. Here are the four ways peering fails silently — and the one way it fails loudly.
You created a VPC peering connection. The console says Active. You try to reach a database in the other VPC and the connection just… hangs. No error. No rejected packet. No log line pointing at the problem. It times out, and nothing tells you why.
That silence is the whole problem with VPC peering. A peering connection being “active” means the two VPCs agreed to peer — nothing more. It says nothing about whether traffic can actually flow. Almost everything that makes traffic flow is configured somewhere else, and when one of those pieces is missing, the failure mode is silence.
Here are the four ways peering fails without telling you, and the one way it fails loudly.
“Active” is not “connected”
Accepting a peering connection is a handshake, not a data path. Once it’s active, you still have to tell each VPC how to route to the other, and you have to let the traffic through at the security layer. Miss any of that and packets don’t get rejected with a helpful error — they just go nowhere. Start every peering debug from that assumption: active means the door exists, not that anyone can walk through it.
Failure 1: You only added the route on one side
This is the most common one. A peering connection does nothing until each VPC’s route table knows to send the peer’s CIDR range across it. Per AWS’s own docs:
The owner of each VPC in the VPC peering connection must manually add a route to one or more of their VPC route tables that points to the IP address range of the other VPC.
The key word is each. Routing has to be added in both VPCs. Add the route in VPC A pointing at B’s CIDR, forget the reverse route in B, and your request reaches B just fine — but B’s response has no route back. From the client side, that looks identical to a total failure: a hang, then a timeout. Half a route is a silent failure.
Failure 2: The security group never allowed the peer
Routing gets the packet to the subnet. The destination’s security group decides whether it’s allowed in. Peering doesn’t change that — the target instance’s security group still needs an inbound rule that permits the source, and a missing rule is dropped silently, exactly like any other security-group deny.
Same region, you can write that rule cleanly by referencing the peer’s security group directly:
You can update the inbound or outbound rules for your VPC security groups to reference security groups in the peered VPC.
Here’s the trap. That convenience does not exist across regions:
You cannot reference the security group of a peer VPC that’s in a different Region. Instead, use the CIDR block of the peer VPC.
So a rule that worked perfectly in a same-region setup — “allow from sg-0abc…” — has no cross-region equivalent. Move the peer to another region and you have to rewrite those rules against CIDR ranges instead. If you copy a same-region pattern into an inter-region peering, the security layer quietly won’t do what you think it does.
Failure 3: You assumed peering is transitive
You peer VPC A to VPC B, and VPC A to VPC C, and then expect B and C to talk. They won’t:
VPC peering does not support transitive peering relationships. For example, if there are VPC peering connections between VPC A and VPC B, and between VPC A and VPC C, you can’t route traffic from VPC B to VPC C through VPC A.
Peering is strictly point-to-point. Traffic doesn’t hop through a shared VPC to reach a third one. The same non-transitivity applies to A’s gateways: resources in a peered VPC can’t use VPC A’s internet gateway, NAT device, or VPN connection to reach the outside world. If your mental model is “everyone peered to the hub can reach everyone else,” the connections you never made are the ones that fail — silently, because nothing was ever misconfigured, it just was never going to work.
Failure 4: DNS resolves to the public IP
Even with routes and security groups correct, private DNS resolution across a peering connection is off by default. You have to explicitly turn it on — the setting lets a VPC:
resolve public IPv4 DNS hostnames to private IPv4 addresses when queried from instances in the peer VPC.
Without it, a hostname in the peer VPC resolves to a public IP instead of the private one. The name resolves, so nothing looks broken — but the traffic is now aimed at a public address instead of crossing the peering link privately, and depending on your routing it either takes the wrong path or goes nowhere. A working DNS lookup pointing at the wrong IP is about as silent as a failure gets.
The one failure that’s actually loud
For contrast, here’s the peering mistake that does tell you immediately: overlapping address space.
You cannot create a VPC peering connection between VPCs that have matching or overlapping IPv4 CIDR blocks.
Try to peer two VPCs whose CIDRs overlap and the request fails at creation, right away, with an error. This is the exception that proves the rule — AWS catches the one problem it can see at config time. Every other failure on this list happens after the connection is active, in a layer AWS won’t validate for you, which is exactly why they stay silent until traffic doesn’t flow.
Catch it before you deploy
Every silent failure above is visible before anything is deployed — it’s in the topology, not the runtime. Walk the connection on paper (or on a diagram) and check:
- Routes in both VPCs’ route tables, each pointing at the other’s CIDR — not just the side you started from.
- A security-group inbound rule on the destination that allows the source — by SG reference same-region, by CIDR cross-region.
- NACLs on both subnets allowing the traffic in both directions.
- No reliance on transitivity — every pair that needs to talk has its own peering connection.
- DNS resolution enabled on the peering connection if you’re addressing resources by hostname.
- Non-overlapping CIDRs (this one AWS will enforce for you).
This is the class of mistake Design Beaver is built to catch: the connection that looks fine on the canvas but doesn’t actually hold up. It validates as you draw — today it flags things like a private-subnet resource with no route out and a service trying to reach a database it can’t actually connect to, so the reachability gap shows up while you’re designing, not after a deploy goes quiet. If you’re tired of finding out about a dead path from a timeout, open Design Beaver — it’s live in beta, free, no account required.
Try Design Beaver on your own architecture
It’s live in beta — free, in your browser, no account required.
Open the app →Prefer email? Get new features in your inbox: