diff --git a/lib/bouncer/backends/v0/accept.go b/lib/bouncer/backends/v0/accept.go
index 49c2866d24d90c5a8e653ca43ac5c79b41dea06c..e9ff29b4cf7b71dee6fd935d3740ce70acdd74bc 100644
--- a/lib/bouncer/backends/v0/accept.go
+++ b/lib/bouncer/backends/v0/accept.go
@@ -223,7 +223,7 @@ func startup1(server zap.ReadWriter, parameterStatus map[string]string) (done bo
 		return false, nil
 	default:
 		err = ErrUnexpectedPacket
-		return false, err
+		return
 	}
 }
 
diff --git a/lib/gat/configs/pgbouncer/config.go b/lib/gat/configs/pgbouncer/config.go
index aa464449a8a561704e0661e5e810e32d921174b1..b52d3a50df8487fe00375521de2bbb043dec19b5 100644
--- a/lib/gat/configs/pgbouncer/config.go
+++ b/lib/gat/configs/pgbouncer/config.go
@@ -2,14 +2,17 @@ package pgbouncer
 
 import (
 	"errors"
+	"log"
 	"net"
+	"os"
 	"strconv"
 	"time"
 
 	"pggat2/lib/gat"
 	"pggat2/lib/gat/pools/session"
 	"pggat2/lib/gat/pools/transaction"
-	"pggat2/lib/util/ini"
+	ini2 "pggat2/lib/util/encoding/ini"
+	"pggat2/lib/util/encoding/userlist"
 )
 
 type PoolMode string
@@ -248,19 +251,32 @@ var Default = Config{
 }
 
 func Load() (Config, error) {
-	conf, err := ini.ReadFile("pgbouncer.ini")
+	conf, err := ini2.ReadFile("pgbouncer.ini")
 	if err != nil {
 		return Config{}, err
 	}
 
 	var c = Default
-	err = ini.Unmarshal(conf, &c)
+	err = ini2.Unmarshal(conf, &c)
 	return c, err
 }
 
 func (T *Config) ListenAndServe(pooler *gat.Pooler) error {
+	var authFile map[string]string
+	if T.PgBouncer.AuthFile != "" {
+		file, err := os.ReadFile(T.PgBouncer.AuthFile)
+		if err != nil {
+			return err
+		}
+
+		authFile, err = userlist.Unmarshal(file)
+		if err != nil {
+			return err
+		}
+	}
+
 	for name, user := range T.Users {
-		u := gat.NewUser("pw") // TODO(garet) passwords
+		u := gat.NewUser(authFile[name]) // TODO(garet) passwords
 		pooler.AddUser(name, u)
 
 		for dbname, db := range T.Databases {
@@ -305,12 +321,27 @@ func (T *Config) ListenAndServe(pooler *gat.Pooler) error {
 				// connect over unix socket
 				// TODO(garet)
 			} else {
+				var address string
+				if db.Port == 0 {
+					address = net.JoinHostPort(db.Host, "5432")
+				} else {
+					address = net.JoinHostPort(db.Host, strconv.Itoa(db.Port))
+				}
+
+				var password string
+				if db.Password == "" {
+					// lookup password
+					password = authFile[name]
+				} else {
+					password = db.Password
+				}
+
 				// connect over tcp
 				recipe := gat.TCPRecipe{
 					Database:          db.DBName,
-					Address:           db.Host,
+					Address:           address,
 					User:              name,
-					Password:          "pw",
+					Password:          password,
 					MinConnections:    db.MinPoolSize,
 					MaxConnections:    db.MaxDBConnections,
 					StartupParameters: startupParameters,
@@ -327,7 +358,9 @@ func (T *Config) ListenAndServe(pooler *gat.Pooler) error {
 		}
 	}
 
-	return pooler.ListenAndServe(
-		net.JoinHostPort(T.PgBouncer.ListenAddr, strconv.Itoa(T.PgBouncer.ListenPort)),
-	)
+	listen := net.JoinHostPort(T.PgBouncer.ListenAddr, strconv.Itoa(T.PgBouncer.ListenPort))
+
+	log.Println("listening on", listen)
+
+	return pooler.ListenAndServe(listen)
 }
diff --git a/lib/gat/pool.go b/lib/gat/pool.go
index d72bf5b8632e9a76a7ac8b5fc7fba79e47e8b57d..faed75e1e7e728ab30e2454aa402b8fd01791da1 100644
--- a/lib/gat/pool.go
+++ b/lib/gat/pool.go
@@ -57,29 +57,31 @@ func NewPool(raw RawPool, idleTimeout time.Duration) *Pool {
 		}
 	}()
 
-	go func() {
-		for {
-			var wait time.Duration
+	if idleTimeout != 0 {
+		go func() {
+			for {
+				var wait time.Duration
+
+				now := time.Now()
+				idle := pool.IdleSince()
+				for now.Sub(idle) > idleTimeout {
+					if idle == (time.Time{}) {
+						break
+					}
+					pool.ScaleDown(1)
+					idle = pool.IdleSince()
+				}
 
-			now := time.Now()
-			idle := pool.IdleSince()
-			for now.Sub(idle) > idleTimeout {
 				if idle == (time.Time{}) {
-					break
+					wait = idleTimeout
+				} else {
+					wait = now.Sub(idle.Add(idleTimeout))
 				}
-				pool.ScaleDown(1)
-				idle = pool.IdleSince()
-			}
 
-			if idle == (time.Time{}) {
-				wait = idleTimeout
-			} else {
-				wait = now.Sub(idle.Add(idleTimeout))
+				time.Sleep(wait)
 			}
-
-			time.Sleep(wait)
-		}
-	}()
+		}()
+	}
 
 	return pool
 }
diff --git a/lib/util/ini/readfile.go b/lib/util/encoding/ini/readfile.go
similarity index 100%
rename from lib/util/ini/readfile.go
rename to lib/util/encoding/ini/readfile.go
diff --git a/lib/util/ini/unmarshal.go b/lib/util/encoding/ini/unmarshal.go
similarity index 100%
rename from lib/util/ini/unmarshal.go
rename to lib/util/encoding/ini/unmarshal.go
diff --git a/lib/util/ini/unmarshal_test.go b/lib/util/encoding/ini/unmarshal_test.go
similarity index 100%
rename from lib/util/ini/unmarshal_test.go
rename to lib/util/encoding/ini/unmarshal_test.go
diff --git a/lib/util/encoding/userlist/unmarshal.go b/lib/util/encoding/userlist/unmarshal.go
new file mode 100644
index 0000000000000000000000000000000000000000..94444d2be6a497be824a474ecbd23f44bfb6d8b6
--- /dev/null
+++ b/lib/util/encoding/userlist/unmarshal.go
@@ -0,0 +1,42 @@
+package userlist
+
+import (
+	"bytes"
+	"errors"
+	"strconv"
+)
+
+func Unmarshal(data []byte) (map[string]string, error) {
+	var res = make(map[string]string)
+
+	var line []byte
+	for {
+		line, data, _ = bytes.Cut(data, []byte{'\n'})
+		line = bytes.TrimSpace(line)
+		if len(line) == 0 {
+			if len(data) == 0 {
+				break
+			}
+
+			continue
+		}
+
+		fields := bytes.Fields(line)
+		if len(fields) < 2 {
+			return nil, errors.New("expected \"key\" \"value\"")
+		}
+
+		key, err := strconv.Unquote(string(fields[0]))
+		if err != nil {
+			return nil, err
+		}
+		value, err := strconv.Unquote(string(fields[1]))
+		if err != nil {
+			return nil, err
+		}
+
+		res[key] = value
+	}
+
+	return res, nil
+}
diff --git a/pgbouncer.ini b/pgbouncer.ini
new file mode 100644
index 0000000000000000000000000000000000000000..5ce00217d8bb9e16f5c1024424ed8b24cb1dfd4c
--- /dev/null
+++ b/pgbouncer.ini
@@ -0,0 +1,10 @@
+[pgbouncer]
+mode = transaction
+auth_file = userlist.txt
+
+[users]
+postgres =
+
+[databases]
+uniswap = host=localhost
+postgres = host=localhost
diff --git a/userlist.txt b/userlist.txt
new file mode 100644
index 0000000000000000000000000000000000000000..7ceb0c53575ddb050eb244e225b2544f137c2eaf
--- /dev/null
+++ b/userlist.txt
@@ -0,0 +1 @@
+"postgres" "password"