Comparing PlanetScale PostgreSQL with Hetzner Local Postgres

Published on Thursday, November 13, 2025

PlanetScale’s new $5 single-node PostgreSQL tier (PS-5) promises the same observability/maintenance story you get from their Vitess-backed MySQL side. I wanted to see how it feels next to the very boring Postgres instance I already pay for: a Hetzner CPX11 (2 vCPU / 2 GB RAM for €3.85) running in their eu-central region (Nuremberg). This isn’t even LAN vs internet—it’s literally local disk vs a remote region—so the goal is to get a sanity check, not crown a winner.

I pointed the usual pgbench mix at PlanetScale’s x64 PS-5, PS-10, PS-20, PS-40, PS-80, and PS-160 plans. I asked for eu-central-1 to keep everything close to the Hetzner VPS, but PlanetScale split the replicas across eu-central-1 and eu-central-2, so we roll with what they provisioned. Each plan got hit via the direct endpoint and via PgBouncer. The Hetzner box got the same treatment so we can see how much pooling narrows the gap. Everything lives in mhmd-azeez/hetzner_vs_planetscale if you want to re-run or tweak the tests.

Direct connections

First pass: raw connections, no pooling tricks, single region hops only.

TPS (transactions/second)

concurrency local ps5 ps10 ps20 ps40 ps80 ps160
1 406.97 29.43 24.70 24.67 23.59 28.50 24.11
10 2,445.69 256.03 261.99 278.28 257.12 268.42 272.31
50 2,487.99 - - - - - 1,245.58
Direct connection TPS
Higher is better — hover to inspect each plan

Latency (ms)

concurrency local ps5 ps10 ps20 ps40 ps80 ps160
1 2.46 33.98 40.49 40.53 42.38 35.09 41.48
10 4.09 39.06 38.17 35.93 38.89 37.26 36.72
50 20.10 - - - - - 40.14
Direct connection latency
Lower is better — median latency in milliseconds

PgBouncer

Next pass: slap PgBouncer in front of everything and see how far we can push concurrency before the network becomes the wall.

TPS

concurrency local ps5 ps10 ps20 ps40 ps80 ps160
1 275.29 23.50 26.13 22.61 24.53 27.17 21.72
10 1,645.86 256.16 264.75 253.11 259.09 260.90 265.06
50 1,676.38 397.54 458.44 479.10 477.70 1,204.07 1,207.27
100 1,719.79 396.29 464.93 485.40 473.24 1,200.39 2,137.35
200 1,712.10 397.50 460.53 481.65 474.73 1,196.91 2,165.73
400 1,693.84 398.24 465.79 477.23 471.96 - -
PgBouncer TPS
Higher is better — how pooling scales past 400 concurrent clients

Latency (ms)

concurrency local ps5 ps10 ps20 ps40 ps80 ps160
1 3.63 42.56 38.27 44.22 40.77 36.81 46.05
10 6.08 39.04 37.77 39.51 38.60 38.33 37.73
50 29.83 125.77 109.07 104.36 104.67 41.53 41.42
100 58.15 252.34 215.09 206.02 211.31 83.31 46.79
200 116.82 503.15 434.28 415.24 421.29 167.10 92.35
400 236.15 1,004.42 858.76 838.18 847.53 - -
PgBouncer latency
Lower is better — watch how the network hop compounds the tail

Takeaways

  • Latency is the tax: even PS-160 stays ~10× slower on single-connection round trips because physics wins.
  • Pooling earns its keep: once PgBouncer gets involved, PS-160 eventually outruns the local box at extreme concurrency simply because it can hold more connections open at once.
  • Small plans hit ceilings fast: PS-5/10/20 tap out before the 50-connection mark, so plan accordingly if you expect chatty workloads.
  • You still pay for the managed bits: backups, maintenance, branches, and observability are the real pitch for PlanetScale; Hetzner only wins if you’re happy being your own DBA.