← блог

Supabase «max clients reached in session mode» на Vercel и исправление, которое сделало хуже

20 сентября 2026 г. · 7 мин чтения

Ошибка звучит так: (EMAXCONNSESSION) max clients reached in session mode - max clients are limited to pool_size: 15. Наш API начал её возвращать, а маркетинговый сайт оставался полностью здоровым. Он просто не трогает Postgres. Именно поэтому такие сбои остаются незамеченными. Выглядят нормально как раз те части, которым база не нужна.

Ниже о том, что значит эта ошибка, о двух ошибках, которые мы допустили при исправлении, и о строке подключения, которая реально работает с Vercel.

Два пулера, два порта

Почему serverless исчерпывает session mode

Каждый тёплый экземпляр функции держит свой маленький пул. Наш держал три подключения. Пул в session mode не отдаёт подключения, пока экземпляр тёплый. Пять тёплых экземпляров это пятнадцать подключений, то есть лимит. Шестой запрос откуда угодно падает.

Демон парка, который каждые несколько секунд опрашивал три эндпоинта, держал экземпляры тёплыми круглые сутки. Ничего необычного в этом нет. Это просто арифметика, в которой session mode проигрывает.

Ошибка первая: начали чинить не тот уровень

Срочное исправление было таким: max: 1 на экземпляр и таймаут простоя двадцать секунд, всё ещё в session mode. Это сработало. Затихшие экземпляры отдавали свой слот, и API восстановился за несколько минут. Потом мы перевели строку подключения на режим транзакций, и это было правильно. А max: 1 оставили, и это было неправильно.

Ошибка вторая: пул из одного подключения в режиме транзакций

В режиме транзакций одно подключение на экземпляр выстраивает все запросы этого экземпляра в очередь к одной трубе. Опросы демона копились за ним. Запросы превышали свой двадцатисекундный лимит, и симптом сменился с ошибок 500 на зависания. Маркетинговый сайт по-прежнему был быстрым. API перестал отвечать совсем.

Режим транзакций возвращает подключение после каждой транзакции, поэтому ему нужен пул обычного размера. Мы поставили восемь, и таймауты прекратились.

Как заметить заранее

Пулер ничего не скажет, пока не откажет. А сам Postgres скажет, если спросить.

select application_name, state, count(*)
from pg_stat_activity
where datname = 'postgres'
group by 1, 2
order by 3 desc;

Выполните это через подключение в session mode при обычной нагрузке на приложение. Если число ползёт к лимиту, а большинство строк в состоянии idle, до ошибки одна загруженная минута. В режиме транзакций тот же запрос показывает, что подключения переиспользуются, а не копятся.

Строка подключения, которая реально работает

postgresql://postgres.<project-ref>:<password>@aws-0-<region>.pooler.supabase.com:6543/postgres
  • Хост это пулер, а не db.<ref>.supabase.co. Панель Supabase может показывать прямой хост под заголовком transaction pooler. Это всё равно прямой хост.
  • Имя пользователя postgres.<project-ref> на пулере. Просто postgres работает только на прямом хосте.
  • Прямой хост доступен только по IPv6, если не купить дополнение IPv4. У него есть запись AAAA и нет записи A. Функции Vercel до него не достают, да и порт 6543 там всё равно закрыт.
  • Строка запроса не нужна для postgres.js. Задайте prepare: false. Флаг ?pgbouncer=true это соглашение Prisma.
  • Миграции оставьте на 5432. Drizzle и похожим инструментам нужно подключение в session mode. Направьте развёрнутое приложение на 6543, а локальное окружение для миграций на 5432.
$ dig +short A    db.<project-ref>.supabase.co     # (nothing)
$ dig +short AAAA db.<project-ref>.supabase.co     # 2600:1f18:...
$ nc -z aws-0-us-east-1.pooler.supabase.com 6543   # succeeded

Размеры в одной таблице

И последнее, что стоит знать. Пока всё это происходило, демон, который не мог достучаться до API, решил, что все машины под его управлением мертвы. Он приготовился перезапустить им питание. Эта история в посте как лимит подключений к базе данных чуть не перезагрузил Mac моих клиентов.

Вопросы

Какой порт Supabase использовать приложению на Vercel?
6543, пулер в режиме транзакций. Session mode на 5432 держит одно серверное подключение на клиента и ограничивает проект 15 подключениями. Serverless быстро их исчерпывает.
Почему db.<project-ref>.supabase.co не подключается с Vercel?
У прямого хоста есть только IPv6-адрес, если не платить за дополнение IPv4. А функции Vercel не достают до него по IPv6. Используйте хост пулера, aws-0-<region>.pooler.supabase.com.
Какое имя пользователя нужно пулеру?
postgres.<project-ref>, с добавленным ref проекта. Просто postgres работает только на прямом хосте.
Нужен ли ?pgbouncer=true в строке подключения?
Для Prisma да. Для postgres.js вместо этого задайте prepare: false в настройках клиента. Режим транзакций не поддерживает подготовленные запросы.
Какой размер пула нужен для каждого режима?
Session mode: одно или два на экземпляр с коротким таймаутом простоя, потому что лимит пятнадцать. Режим транзакций: обычный пул, от пяти до десяти, потому что подключения возвращаются после каждой транзакции.

Посчитайте свои цифры в калькуляторе или арендуйте раннер.