Every client connection to PostgreSQL occupies a slot, and the number of slots is max_connections. The documentation gives its default as typically 100, notes it can only be set at server start, and is explicit that it is not free: PostgreSQL sizes certain resources, including shared memory, directly from it. When the slots run out, new connections are refused with SQLSTATE 53300, too_many_connections, in the class the documentation calls Insufficient Resources.
With the default settings there are two different refusals, and telling them apart is most of the diagnosis. On PostgreSQL 16, setting reserved_connections above 0 adds a third, which turns away roles without pg_use_reserved_connections first: remaining connection slots are reserved for roles with privileges of the "pg_use_reserved_connections" role. A few slots are held back for administrators — superuser_reserved_connections, default three. Once only those reserved slots remain, an ordinary role is turned away with FATAL: remaining connection slots are reserved for roles with the SUPERUSER attribute, while a superuser can still get in. Only when every slot is gone does anyone, superuser included, get FATAL: sorry, too many clients already. Both wordings were reproduced on PostgreSQL 16 for this page; versions before 16 phrase the first one differently, so match on the meaning rather than the exact string.
That makes the first message good news of a kind. It means the database is protecting a way in for you to investigate, and your application is the thing that is full. Connect as a superuser and look before changing anything.
The usual cause is not traffic. It is how many connections the application holds open, which is decided by its connection pool and by how many copies of the application are running. Ten replicas with a pool of twenty is two hundred connections whether or not anybody is using the site, and scaling the application out multiplies the number without any change to the database at all.
The other common cause is connections that are open but useless. A session that began a transaction and then stopped sending queries shows as idle in transaction. It holds its slot, keeps any locks it took, and — the documentation notes — an open transaction also prevents vacuuming away recently-dead rows, so it degrades the database while it sits there. A plain idle connection outside a transaction is far cheaper: the documentation says it imposes no large costs on the server.