Un pool de conexiones Postgres sano es la base para que una aplicación escale, pero ciertos descuidos en el código pueden «envenenarlo» y dejarlo inutilizable. PlanetScale explica en este artículo técnico qué es un pool de conexiones, por qué los modos de PgBouncer en los que las conexiones se reutilizan entre clientes —como el transaction mode, que es el predeterminado en su plataforma— pueden quedarse atascados en estados como el de solo lectura, y cómo detectarlo y resolverlo.
El envenenamiento se produce cuando un cliente deja la conexión subyacente en un estado no deseado y el siguiente cliente que la reutiliza hereda ese estado. Un patrón habitual es ejecutar SET SESSION CHARACTERISTICS AS TRANSACTION READ ONLY dentro de una API pensando que el cambio se limita a esa transacción, cuando en realidad persiste en la sesión. A partir de ahí, cualquier INSERT devuelva el error «cannot execute INSERT in a read-only transaction» (código 25006), que no debe confundirse con el de un clúster en modo lectura.
La solución inmediata es ejecutar DISCARD ALL sobre cada conexión del pool —algo que con el CLI de PlanetScale o un script paralelo se puede hacer de forma masiva—, pero la solución de fondo exige revisar el código que modifica variables de sesión, huir de transacciónes sin ROLLBACK y, siempre que sea posible, derivar el tráfico de lectura a una réplica. Herramientas como el servidor MCP de PlanetScale, combinado con ORMs como Drizzle y su soporte de enrutado a réplicas, ayudan a automatizar la detección y corrección del problema.
