Un pool de conexiones es un conjunto de conexiones a la base de datos ya abiertas que una aplicación reutiliza, en lugar de abrir una nueva cada vez que necesita hablar con la base. Para entender por qué importa hay que saber algo contraintuitivo: abrir una conexión a la base de datos es caro. Parece instantáneo, pero por dentro implica una negociación de red, autenticación, y reservar recursos en el servidor —es una de las operaciones más costosas que hace una aplicación—. Si la aplicación abre y cierra una conexión en cada petición (el patrón ingenuo), paga ese coste una y otra vez, lo que mata el rendimiento: gran parte del tiempo de cada petición se va en conectar, no en hacer el trabajo. Y hay un problema peor bajo carga: cada conexión consume recursos en el servidor de base de datos, que tiene un límite de conexiones simultáneas. Si llegan muchos usuarios a la vez y cada uno abre su conexión, se puede agotar ese límite y tumbar la base de datos para todos. El pool resuelve ambos problemas. Al arrancar, abre un número fijo de conexiones y las mantiene listas. Cuando la aplicación necesita una, toma prestada una del pool (instantáneo, ya está abierta), la usa, y al terminar la devuelve al pool para que otra petición la reutilice —no la cierra—. Así, el coste de abrir se paga una sola vez por conexión, no en cada petición, y el número de conexiones al servidor queda acotado al tamaño del pool, sin importar cuántos usuarios lleguen. Dimensionarlo es un equilibrio: pocas conexiones y las peticiones hacen cola esperando una libre; demasiadas y se sobrecarga el servidor de base de datos. El tamaño óptimo suele ser bastante menor de lo que la intuición sugiere. El pool es, junto con los índices, una de las claves del rendimiento y la escalabilidad de cualquier aplicación que use una base de datos.
Ver índice de contenidos
El coste de conectar
El punto de partida es un hecho que sorprende: abrir una conexión a la base de datos es una operación cara. Desde el código parece que conectar es instantáneo —una línea y ya está—, pero por debajo pasa mucho: se establece una conexión de red, se autentica el usuario y la contraseña, se negocian parámetros, y el servidor reserva recursos (memoria, procesos) para atender esa conexión. Todo eso lleva tiempo y consume recursos. No es un problema si conectás una vez y usás la conexión mucho rato, pero se vuelve un desastre si se hace constantemente.
Dos problemas: lentitud y saturación
El patrón ingenuo —abrir una conexión en cada petición y cerrarla al terminar— provoca dos problemas distintos. El primero es de rendimiento: como abrir es caro, cada petición desperdicia una parte importante de su tiempo solo en conectar, antes de hacer el trabajo útil. En una aplicación con muchas peticiones pequeñas, el coste de conectar puede superar al de la consulta en sí, así que la aplicación va lenta por un motivo que no tiene nada que ver con las consultas. El segundo problema es de saturación, y es peor: cada conexión abierta consume recursos en el servidor de base de datos, que tiene un límite máximo de conexiones simultáneas. Bajo carga —muchos usuarios a la vez—, si cada uno abre su propia conexión, se puede alcanzar ese límite, y cuando se alcanza, la base de datos rechaza conexiones nuevas o se colapsa, dejando fuera a todos los usuarios. Es decir, no solo va lento: bajo carga, se cae. El pool ataca ambos problemas a la vez.
Qué es un pool
El pool de conexiones es la solución, y su funcionamiento es un ciclo de prestar y devolver:
| Momento | Qué hace el pool |
|---|---|
| Al arrancar | Abre un número fijo de conexiones y las mantiene listas |
| La app pide una | Le presta una conexión ya abierta (instantáneo) |
| La app termina | Devuelve la conexión al pool, no la cierra |
| Otra petición | Reutiliza esa misma conexión que quedó libre |
La idea central del pool es reemplazar «abrir y cerrar» por «prestar y devolver». En vez de que cada petición abra su conexión (cara) y la cierre al terminar, el pool abre unas cuantas conexiones al inicio y las mantiene vivas. Cuando una petición necesita hablar con la base, el pool le presta una de esas conexiones ya abiertas —operación instantánea, porque el coste de abrirla ya se pagó—; la petición hace su consulta o su transacción, y al terminar devuelve la conexión al pool en vez de cerrarla, dejándola disponible para la siguiente petición. Así, el costoso trabajo de abrir se hace una sola vez por conexión (al arrancar el pool), y a partir de ahí las peticiones se sirven a coste casi cero. Un detalle importante: cuando una conexión vuelve al pool debe quedar «limpia» —sin transacciones a medias ni estado de la petición anterior—, porque la va a usar otra petición; los pools se encargan de esto, pero es la razón por la que hay que devolver siempre la conexión (no «olvidarse» de soltarla), o el pool se queda sin conexiones disponibles. Hay pools dentro de la aplicación (parte de la librería que conecta a la base) y pools externos como intermediarios (por ejemplo, PgBouncer para PostgreSQL), pero el concepto es el mismo.
Dimensionarlo
La decisión clave al usar un pool es su tamaño: cuántas conexiones mantiene. Es un equilibrio, y errar por cualquiera de los dos lados tiene consecuencias:
| Tamaño | Consecuencia |
|---|---|
| Demasiado pequeño | Las peticiones hacen cola esperando una conexión libre: latencia |
| Demasiado grande | Sobrecarga el servidor de base de datos: puede degradarlo o tumbarlo |
| Justo | Suficientes para el trabajo simultáneo real, sin saturar el servidor |
El error más común al dimensionar un pool es hacerlo demasiado grande, con la idea intuitiva de que «más conexiones = más rápido». Es al revés: un pool excesivo abre muchas conexiones al servidor, y como cada una consume recursos, un número alto puede sobrecargar la base de datos —hacerla más lenta para todos, o incluso alcanzar su límite y tumbarla, que es justo el problema que queríamos evitar—. La realidad, contraintuitiva, es que el tamaño óptimo suele ser bastante menor de lo que uno esperaría: una base de datos atiende las consultas con un número limitado de recursos (procesadores, discos), y a partir de cierto punto, más conexiones simultáneas no hacen el trabajo más rápido, solo compiten entre sí y añaden sobrecoste. Es mejor tener pocas conexiones muy usadas que muchas conexiones peleándose por los recursos. La regla práctica: dimensionar el pool según el trabajo realmente simultáneo que puede hacer el servidor, no según el número de usuarios —muchos usuarios pueden compartir pocas conexiones si cada consulta es breve—, y medir antes de agrandar. Si las peticiones hacen cola, quizá el problema no sea que falten conexiones, sino que las consultas son lentas (ahí ayudan los índices) o que la base está saturada. Agrandar el pool para tapar consultas lentas empeora las cosas.
Errores frecuentes
- Abrir y cerrar una conexión en cada petición. Paga el coste de conectar cada vez; usar un pool.
- Dimensionar el pool demasiado grande. Sobrecarga el servidor; el óptimo suele ser menor de lo que parece.
- No devolver la conexión al pool. Si no se suelta, el pool se queda sin conexiones y todo se bloquea.
- Dejar transacciones a medias al devolver la conexión. La siguiente petición hereda un estado sucio; devolver la conexión limpia.
- Agrandar el pool para tapar consultas lentas. No resuelve la lentitud y sobrecarga la base; optimizar las consultas.
- Ignorar el límite de conexiones del servidor. La suma de todos los pools no debe superarlo.
- Creer que más conexiones es más rápido. A partir de cierto punto, compiten por los recursos y ralentizan.
Preguntas frecuentes
¿Qué es un pool de conexiones?
Un pool de conexiones es un conjunto de conexiones a la base de datos que se mantienen abiertas y listas para ser usadas, y que una aplicación reutiliza en lugar de abrir una conexión nueva cada vez que necesita comunicarse con la base de datos. Para entender su utilidad hay que partir de un hecho que resulta contraintuitivo, que es que abrir una conexión a una base de datos es una operación cara. Aunque desde el código de la aplicación parezca que conectarse es instantáneo, por debajo se produce una negociación de red, una autenticación del usuario y la contraseña, la negociación de parámetros y la reserva de recursos en el servidor de la base de datos, todo lo cual lleva tiempo y consume recursos, siendo una de las operaciones más costosas que realiza una aplicación. Si una aplicación abre y cierra una conexión en cada una de las peticiones que atiende, paga ese coste una y otra vez, lo que perjudica gravemente el rendimiento, ya que una parte importante del tiempo de cada petición se dedica simplemente a conectarse en lugar de a realizar el trabajo útil. Además, cada conexión abierta consume recursos en el servidor de base de datos, que tiene un límite máximo de conexiones simultáneas, de modo que bajo mucha carga, si cada usuario abre su propia conexión, se puede agotar ese límite y tumbar la base de datos para todos. El pool de conexiones resuelve estos problemas manteniendo un conjunto de conexiones ya abiertas. Al arrancar, el pool abre un número determinado de conexiones y las mantiene listas. Cuando la aplicación necesita comunicarse con la base de datos, el pool le presta una de esas conexiones ya abiertas, lo cual es instantáneo porque el coste de abrirla ya se pagó, la aplicación la usa para su consulta o transacción, y al terminar la devuelve al pool en lugar de cerrarla, quedando disponible para que otra petición la reutilice. De este modo, el costoso trabajo de abrir una conexión se realiza una sola vez por conexión, al arrancar el pool, y a partir de ahí las peticiones se sirven a un coste casi nulo, y además el número de conexiones al servidor queda acotado al tamaño del pool, con independencia de cuántos usuarios lleguen. Por todo ello, el pool de conexiones es una de las claves del rendimiento y la escalabilidad de cualquier aplicación que use una base de datos.
¿Por qué es caro abrir una conexión a la base de datos?
Abrir una conexión a una base de datos es una operación cara porque, aunque desde el código parezca instantánea, implica por debajo una serie de pasos costosos en tiempo y en recursos, como el establecimiento de una conexión de red, la autenticación, la negociación de parámetros y la reserva de recursos en el servidor. Este coste es una de las cosas que más sorprende a quien empieza, ya que en el código de una aplicación conectarse a la base de datos suele ser una simple instrucción que da la impresión de ejecutarse al momento, sin dejar ver todo el trabajo que se realiza internamente. El primer paso costoso es el establecimiento de la conexión de red entre la aplicación y el servidor de base de datos, que implica una comunicación inicial para establecer el canal, con su correspondiente ida y vuelta a través de la red, que consume tiempo, especialmente si la base de datos está en otro servidor. El segundo paso es la autenticación, en la que el servidor verifica las credenciales, es decir, el usuario y la contraseña con los que la aplicación se conecta, comprobando que son válidos y que tienen permiso para acceder, lo que también añade tiempo. El tercer paso es la negociación de diversos parámetros de la conexión, como la configuración de la sesión. Y el cuarto, y muy importante, es la reserva de recursos en el servidor de la base de datos, ya que el servidor debe destinar memoria y, en algunos sistemas, crear un proceso o hilo específico para atender esa conexión, lo que consume recursos del servidor mientras la conexión existe. Todo este conjunto de operaciones hace que abrir una conexión sea una de las operaciones más costosas que realiza una aplicación al interactuar con la base de datos. Este coste no supone un problema si la conexión se abre una vez y se utiliza durante mucho tiempo para muchas operaciones, ya que el coste se amortiza. Sin embargo, se convierte en un grave problema si la aplicación abre y cierra una conexión constantemente, por ejemplo una en cada petición que atiende, ya que entonces paga ese coste una y otra vez, desperdiciando tiempo y recursos de forma continua. Es precisamente para evitar pagar repetidamente este coste por lo que existen los pools de conexiones, que mantienen las conexiones abiertas y las reutilizan, de modo que el costoso trabajo de abrirlas se realiza una sola vez por conexión en lugar de en cada uso.
¿Cómo funciona un pool de conexiones?
Un pool de conexiones funciona manteniendo un conjunto de conexiones a la base de datos ya abiertas y gestionándolas mediante un ciclo de prestar y devolver, de modo que la aplicación toma prestada una conexión cuando la necesita y la devuelve al pool cuando termina, en lugar de abrir y cerrar conexiones constantemente. El funcionamiento se puede describir en varias fases. Al arrancar, el pool abre un número determinado de conexiones a la base de datos y las mantiene vivas y listas para ser usadas, pagando en ese momento inicial el coste de abrirlas. Cuando la aplicación necesita comunicarse con la base de datos para realizar una consulta o una transacción, en lugar de abrir una conexión nueva, solicita una al pool, que le presta una de las conexiones que tiene abiertas y disponibles, operación que es prácticamente instantánea porque la conexión ya está abierta y no hay que pagar de nuevo el coste de establecerla. La aplicación utiliza esa conexión prestada para realizar su trabajo con la base de datos, y cuando termina, en lugar de cerrar la conexión, la devuelve al pool, que la marca como disponible de nuevo para que pueda ser prestada a otra petición que la necesite. De este modo, las conexiones se reutilizan una y otra vez, y el costoso trabajo de abrirlas se realiza una sola vez por conexión, al arrancar el pool, en lugar de en cada uso. Un aspecto importante del funcionamiento es que, cuando una conexión se devuelve al pool, debe quedar en un estado limpio, es decir, sin transacciones a medias ni ningún estado residual de la petición anterior, ya que la va a usar otra petición distinta, y los pools se encargan de garantizar esta limpieza. Esta es también la razón por la que es fundamental que la aplicación devuelva siempre las conexiones al pool cuando termina de usarlas, ya que si por un error no las devuelve, esas conexiones quedan retenidas y el pool se va quedando sin conexiones disponibles, hasta el punto de que las peticiones se bloquean esperando una conexión que nunca se libera. En cuanto a su ubicación, existen pools que funcionan dentro de la propia aplicación, como parte de la librería que la conecta a la base de datos, y pools externos que actúan como intermediarios entre la aplicación y la base de datos, pero en ambos casos el concepto y el funcionamiento de prestar y devolver conexiones reutilizables es el mismo.
¿Cómo dimensiono el tamaño del pool?
El tamaño del pool de conexiones se dimensiona buscando un equilibrio, ya que un pool demasiado pequeño hace que las peticiones se queden esperando una conexión libre y un pool demasiado grande sobrecarga el servidor de base de datos, y el tamaño óptimo suele ser bastante menor de lo que la intuición sugiere. Para dimensionarlo correctamente hay que entender las consecuencias de errar por cada lado. Si el pool es demasiado pequeño, es decir, si tiene menos conexiones de las necesarias para atender el trabajo simultáneo, cuando todas sus conexiones están ocupadas las nuevas peticiones tienen que hacer cola esperando a que se libere alguna, lo que añade latencia y ralentiza la aplicación. Si el pool es demasiado grande, abre muchas conexiones al servidor de base de datos, y como cada conexión consume recursos, un número excesivo puede sobrecargar el servidor, haciéndolo más lento para todos o incluso alcanzando su límite de conexiones y tumbándolo, que es justamente el problema que se pretendía evitar. El error más común es dimensionar el pool demasiado grande, guiándose por la idea intuitiva de que más conexiones significan más velocidad, cuando en realidad es al revés a partir de cierto punto. La realidad, que resulta contraintuitiva, es que una base de datos atiende las consultas con un número limitado de recursos físicos, como procesadores y discos, y que a partir de un cierto número de conexiones simultáneas, añadir más no hace que el trabajo se realice más rápido, sino que las conexiones compiten entre sí por esos recursos limitados y añaden una sobrecarga de gestión, degradando el rendimiento. Por ello, es mejor tener pocas conexiones muy usadas que muchas conexiones peleándose por los recursos. La regla práctica para dimensionar el pool es hacerlo en función del trabajo realmente simultáneo que el servidor de base de datos puede realizar, y no en función del número de usuarios de la aplicación, ya que muchos usuarios pueden compartir un número reducido de conexiones si cada consulta es breve y las conexiones se liberan rápidamente. Además, es fundamental medir el comportamiento real antes de agrandar el pool, ya que si las peticiones hacen cola, el problema puede no ser la falta de conexiones sino que las consultas son lentas, en cuyo caso la solución es optimizar las consultas, por ejemplo con índices adecuados, y no aumentar el pool, ya que agrandar el pool para compensar consultas lentas no resuelve la lentitud y encima sobrecarga la base de datos.
¿Qué pasa si no devuelvo una conexión al pool?
Si una aplicación no devuelve una conexión al pool después de usarla, esa conexión queda retenida y no disponible para otras peticiones, y si esto ocurre repetidamente, el pool se va quedando sin conexiones libres hasta agotarse, momento en el cual las nuevas peticiones se bloquean esperando indefinidamente una conexión que nunca se libera, lo que puede llegar a paralizar la aplicación. El funcionamiento del pool se basa en un ciclo de prestar y devolver, en el que la aplicación toma prestada una conexión del pool cuando la necesita y la devuelve cuando termina para que pueda reutilizarse. Este ciclo depende de que las conexiones se devuelvan efectivamente, ya que el pool tiene un número limitado de conexiones y las va prestando a medida que las peticiones las solicitan. Si una petición toma una conexión pero, por un error en el código, no la devuelve al terminar, esa conexión queda permanentemente ocupada desde el punto de vista del pool, aunque la petición ya no la esté usando, lo que se conoce como una fuga de conexiones. Cada fuga reduce en uno el número de conexiones disponibles en el pool. Si las fugas se acumulan, por ejemplo porque un fragmento de código que no devuelve las conexiones se ejecuta muchas veces, el pool va perdiendo conexiones disponibles hasta que se queda sin ninguna. Cuando esto sucede, las nuevas peticiones que solicitan una conexión no encuentran ninguna libre y se quedan esperando a que se libere alguna, pero como las conexiones fugadas nunca se devuelven, esa espera puede ser indefinida, lo que provoca que las peticiones se bloqueen y que la aplicación deje de responder, un problema grave que puede llegar a paralizarla por completo. Por ello, es fundamental que la aplicación devuelva siempre las conexiones al pool cuando termina de usarlas, incluso cuando se produce un error a mitad de una operación, para lo cual se utilizan mecanismos del lenguaje o de la librería que garantizan la devolución de la conexión en todos los casos. Además de devolverlas, es importante que las conexiones se devuelvan en un estado limpio, sin transacciones a medias, para que la siguiente petición que las reutilice no herede un estado incorrecto. Las fugas de conexiones son uno de los problemas más frecuentes y difíciles de diagnosticar en las aplicaciones que usan bases de datos, ya que la aplicación puede funcionar bien durante un tiempo hasta que, tras acumularse suficientes fugas, el pool se agota y todo se bloquea, por lo que gestionar correctamente la devolución de las conexiones es una parte esencial del uso adecuado de un pool.
¿Un pool más grande hace la aplicación más rápida?
No, un pool más grande no hace necesariamente la aplicación más rápida, y de hecho, a partir de cierto punto, un pool demasiado grande puede empeorar el rendimiento e incluso tumbar la base de datos, por lo que la creencia de que más conexiones equivalen a más velocidad es un error común y contraintuitivo. La intuición lleva a pensar que si se aumenta el número de conexiones disponibles, la aplicación podrá atender más trabajo simultáneamente y por tanto irá más rápido, pero esto solo es cierto hasta un cierto límite, y más allá de ese límite el efecto se invierte. La razón está en que una base de datos atiende las consultas utilizando un conjunto limitado de recursos físicos, principalmente los procesadores y los discos del servidor. Estos recursos determinan cuánto trabajo real puede hacer la base de datos de forma simultánea. Cuando el número de conexiones activas se ajusta a la capacidad real del servidor, este trabaja de forma eficiente. Pero cuando el número de conexiones simultáneas supera lo que el servidor puede procesar realmente a la vez, las conexiones adicionales no aceleran el trabajo, sino que compiten entre sí por los mismos recursos limitados, y además cada conexión añade una sobrecarga de gestión al servidor. El resultado es que, en lugar de ir más rápido, la base de datos se ralentiza porque dedica esfuerzo a repartir sus recursos entre demasiadas conexiones y a gestionarlas, y en casos extremos puede alcanzar su límite de conexiones y colapsar, dejando fuera a todos los usuarios. Por ello, la realidad es que suele ser mejor tener pocas conexiones bien aprovechadas que muchas conexiones compitiendo por los recursos, y el tamaño óptimo del pool suele ser bastante menor de lo que la intuición sugiere. La forma correcta de dimensionar el pool es en función del trabajo realmente simultáneo que el servidor puede realizar, teniendo en cuenta sus recursos, y no en función del número de usuarios, ya que muchos usuarios pueden compartir pocas conexiones si las consultas son breves. Además, si la aplicación va lenta y se sospecha que faltan conexiones, antes de agrandar el pool conviene comprobar si el verdadero problema son consultas lentas, ya que en ese caso la solución es optimizar las consultas, por ejemplo mediante índices, y no aumentar el pool, ya que aumentarlo para compensar consultas lentas no soluciona la lentitud y además sobrecarga la base de datos, agravando el problema en lugar de resolverlo.
Fuentes
Documentación oficial y material de la comunidad consultados para esta guía. Fecha de consulta: 28 de julio de 2026.
Aportes de la comunidad Underc0de
- Underc0de, foro. Bases de datos. Rendimiento y escalabilidad.
- Underc0de, foro. Programación general. Conexión de aplicaciones a bases de datos.
Documentación oficial
- PostgreSQL. Connection Settings. Configuración de conexiones.
- PgBouncer. PgBouncer. Pool de conexiones para PostgreSQL.
- Oracle (MySQL). MySQL Documentation. Conexiones y recursos.
- The Twelve-Factor App. Backing services. Recursos de respaldo.