FATAL: too many connections for role "app"
#Что означает ошибка
Для роли PostgreSQL может быть задан лимит одновременных подключений (CONNECTION LIMIT). Когда приложение открывает больше соединений, чем разрешено, новые подключения получают FATAL: too many connections for role. Похожая ошибка про remaining connection slots относится к общему лимиту сервера max_connections (по умолчанию 100). Причины: утечки соединений в приложении, отсутствие пула, слишком много worker-процессов, зависшие транзакции, неправильные постоянные соединения в PHP-FPM.
#Причины
| Возможная причина | Как узнать | Что делать |
|---|---|---|
| Утечка соединенийНе закрываются. | Рост числа сессий. | Закрывайте, используйте пул. |
| Слишком много воркеровphp-fpm. | Всплески нагрузки. | Уменьшите max_children. |
| Нет пулаКаждый запрос создаёт соединение. | Ошибка при пиках. | PgBouncer. |
| Зависшие транзакцииidle in transaction. | Растёт число. | Тайм-аут сессии. |
| Мал лимит ролиCONNECTION LIMIT. | Ошибка для одной роли. | Увеличьте разумно. |
| Слишком высокий max_connectionsПамять. | Тормоза сервера. | Пул вместо увеличения. |
#Порядок
- Выясните лимит роли и текущее число соединенийСообщение
sorry, too many clients alreadyобычно означает исчерпание доступных слотов PostgreSQL, а не обязательно персональный лимит роли. Администратор БД должен подключиться через существующую административную сессию или локальную консоль, если обычные подключения отклоняются. ВpsqlвыполнитеSHOW max_connections;иSELECT state,count(*) FROM pg_stat_activity GROUP BY state;; если нет прав, обратитесь к владельцу СУБД. Сначала соберите показатели, не увеличивайте лимиты вслепую. - Посмотрите список сессий и найдите простаивающиеВ
psqlс нужными правами выполнитеSELECT pid,usename,application_name,client_addr,state,now()-state_change AS idle_for FROM pg_stat_activity ORDER BY state_change LIMIT 50;. Сравнитеidle(ожидание новой команды, нормальное для пулов) иidle in transaction(открытая незавершённая транзакция). Не считайте всеidleлишними: приложение может повторно использовать их. Запишите время, пользователя и имя приложения. - Завершите лишние сессии через pg_terminate_backend
pg_terminate_backend(pid)немедленно разрывает соединение, может откатить текущую транзакцию и вызвать ошибки приложения. Выполняйте его лишь с согласованием после выявления ошибочно зависшей сессии: сначала посмотрите еёpid,stateиquery_start, затем вызовите функцию для КОНКРЕТНОГО PID, избегая своей сессии (pid <> pg_backend_pid()). Не запускайте массовое завершение всехidleили процессов роли на рабочем сервере. - Найдите источник: какое приложение и адрес создают много соединенийПо результатам
pg_stat_activityсгруппируйте соединения поapplication_nameиclient_addr; сопоставьте всплеск с настройками пула приложения или веб-сервера и журналами ошибок за это время. Если приложение создаёт новое соединение на каждый запрос и не закрывает его, исправьте код/пул; увеличениеmax_connectionsлишь отложит новый отказ. - Уменьшите число воркеровЕсли одновременно запущено слишком много процессов PHP-FPM/воркеров, найдите фактический пул и параметр
pm.max_childrenна сервере приложения. Оцените, сколько соединений открывает один процесс, и изменяйте лимит только после измерения нагрузки и согласования: слишком маленький вызовет очередь запросов. Проверьте показатель подключения к PostgreSQL снова после изменения конфигурации приложения, не перезапускайте все службы без необходимости. - Подключите пул соединений PgBouncerЕсли кратковременные запросы создают много одновременных подключений, рассмотрите PgBouncer по официальной документации. Администратор должен настроить отдельный адрес/порт (часто 6432), учётные записи, TLS и подходящий режим пула (
transactionсовместим не с любым использованием состояния сессии), затем протестировать приложение на испытательной базе. Это отдельный проект настройки, а не команда, которую нужно сразу выполнять после завершения сессий. - Закрывайте соединения в приложении и настройтеВ коде приложения убедитесь, что подключение возвращается в пул после выполнения запроса, а транзакции закрываются
COMMITилиROLLBACKи не держатся во время сетевых операций. При систематическихidle in transactionадминистратор может испытатьidle_in_transaction_session_timeoutна тестовом окружении и согласовать допустимое время, но таймаут принудительно завершит зависшие транзакции. - Если нужно, увеличьте лимит роли или max_connectionsУвеличение
max_connections— последнее средство после измерения RAM, размера рабочих процессов и запасных административных слотов. ВpsqlпроверьтеSHOW max_connections;, план изменения согласуйте с администратором: дляmax_connectionsнужен перезапуск сервера, это затронет пользователей. Лимит ролиALTER ROLE ... CONNECTION LIMITотличается от общегоmax_connections, поэтому сначала определите точный тип ошибки и не меняйте оба одновременно. - Команды для отдельных ситуацийВыберите только подходящий вариант. Это не одна последовательность: часть команд диагностирует проблему, а часть меняет настройки или данные.
#Как не допустить повторения
Задайте на уровне приложения максимальный размер пула меньше лимита роли с запасом. Включите мониторинг (pg_stat_activity, Prometheus postgres_exporter). Каждое соединение PostgreSQL занимает около 5–10 МБ памяти, поэтому увеличение max_connections до тысяч без пула приведёт к нехватке RAM.