# PgBouncer FAQ

## How to connect to PgBouncer?

PgBouncer acts as Postgres server, so simply point your client to PgBouncer port.

## How to load-balance queries between several servers?

1. Use a TCP connection load-balancer. Either LVS or HAProxy seem to be good choices. On PgBouncer side it may be good idea to make `server_lifetime` smaller and also turn `server_round_robin` on - by default idle connections are reused by LIFO algorithm which may work not so well when load-balancing is needed.

2. DNS round-robin. Use several IPs behind one DNS name. PgBouncer does not look up DNS each time new connection is launched. Instead it caches all IPs and does round-robin internally. Note: if there is more than 8 IPs behind one name, the DNS backend must support EDNS0 protocol. See README for details.

## How to use SSL connections with PgBouncer?

Use Stunnel. Since version 4.27 it supports PostgreSQL protocol for both client and server side. It is activated by setting `protocol=pgsql`.

For older 4.2x versions the support code is available as patch: stunnel-postgres.diff

Alternative is to use Stunnel on both sides of connection, then the protocol support is not needed.

## How to use prepared statements with session pooling?

In session pooling mode, the reset query must clean old prepared statements.

### Cleaning prepared statements on PostgreSQL 8.3 and newer

This is easy - just set `server_reset_query = DISCARD ALL;` or at least to `DEALLOCATE ALL;`

### Cleaning prepared statements on PostgreSQL 8.2 and older

This is problematic as older versions of PostgreSQL do not allow easy way to drop prepared statements. Luckily there is system view that shows prepared plans in current session. So as a workaround following function can be created:

    CREATE OR REPLACE FUNCTION deallocate_all()
    RETURNS void AS $$
    DECLARE
        sql text;
    BEGIN
        FOR sql IN
            SELECT 'deallocate ' || quote_ident(name)
              FROM pg_catalog.pg_prepared_statements
        LOOP
            EXECUTE sql;
        END LOOP;
    END;
    $$ LANGUAGE plpgsql;

Then the `server_reset_query` can be set to call it:

    server_reset_query = RESET ALL; SET SESSION AUTHORIZATION DEFAULT; SELECT deallocate_all();

## How to use prepared statements with transaction pooling?

To make prepared statements work in this mode would need PgBouncer to keep track of them internally, which it does not do. So only way to keep using PgBouncer in this mode is to disable prepared statements in the client.

### Disabling prepared statements in JDBC

The proper way to do it for JDBC is adding `prepareThreshold=0` parameter to connect string. But current JDBC code ignores the setting for BEGIN/COMMIT/ROLLBACK statements and still tries to cache their plans. This can be fixed with following patch:

http://treehou.se/~omar/postgresql-jdbc-8.4-701-pgbouncer_txn.patch

described here:

http://pgfoundry.org/pipermail/pgbouncer-general/2010-February/000507.html

### Disabling prepared statements in PHP/PDO

To disable use of server-side prepared statements, the PDO attribute `PDO::ATTR_EMULATE_PREPARES` must be set to `true`. Either at connect-time:

    $db = new PDO("dsn", "user", "pass", array(PDO::ATTR_EMULATE_PREPARES => true));

or later:

    $db->setAttribute(PDO::ATTR_EMULATE_PREPARES, true);

## How to upgrade PgBouncer without dropping connections?

This is as easy as launching new PgBouncer process with `-R` switch and same config:

    $ pgbouncer -R -d config.ini

The `-R` (reboot) switch makes new process connect to console of the old process (dbname=pgbouncer) via unix socket and issue following commands:

    SUSPEND;
    SHOW FDS;
    SHUTDOWN;

After that if new one notices old one gone it resumes work with old connections. The magic happens during `SHOW FDS` command which transports actual file descriptors to new process.

If the takeover does not work for whatever reason, the new process can be simply killed, old one notices this and resumes work.

## What should my server_reset_query be?

This depends on pool mode. But in any case there is no need to put `ROLLBACK;` into it, as PgBouncer never re-uses connections where transaction was left open. If client went away in the middle of transaction, the associated server connection will be simply closed.

### Session pooling

    server_reset_query = DISCARD ALL;

This will clean everything.

### Transaction pooling

    server_reset_query =

Yes, empty. In transaction pooling mode the clients should not use any session-based features, so there is no need to clean anything. The `server_reset_query` would only add unnecessary round-trip between transactions and would drop various caches that the next transaction would unnecessarily need to fill again.

## How to know which client is on which server connection?

Use SHOW CLIENTS and SHOW SERVERS views on console.

1. Use `ptr` and `link` to map local client connection to server connection.

2. Use `addr` and `port` of client connection to identify TCP connection from client.

3. Use `local_addr` and `local_port` to identify TCP connection to server.

### Overview of important fields in SHOW CLIENTS

addr + port

  unique port on client host

local_addr + local_port

  pgbouncer port

ptr

  unique id for this connection

link

  unique id for server connection this is currently linked to

### Overview of important fields in SHOW SERVERS

addr + port

  server port this connects to

local_addr + local_port

  unique port on pgbouncer host

ptr

  unique id for this connection

link

  unique id for client connection this is currently linked to

## Should PgBouncer be installed on webserver or database server?

It depends. Installing on webserver is good when short-connections are used, then the connection setup latency is minimised - TCP requires couple of packet roundtrips before connection is usable. Installing on database server is good when there are many different hosts (eg. webservers) connecting to it, then their connections can be optimised together.

It is also possible to install PgBouncer on both webserver and database servers. Only negative aspect of that is that each PgBouncer hop adds small amount of latency to each query. So it’s probably best to simply test whether the payoff is worth the cost.