Now-Next

SaaS architecture

unrecognized configuration parameter in PostgreSQL

Restoring a pg_dump 17 file into PostgreSQL 16 fails with unrecognized configuration parameter transaction_timeout. Measured fixes, plus four other causes.

Chris van Eijk, Now-Next · · 7 min read

ERROR: unrecognized configuration parameter "…" means PostgreSQL does not know the setting named between the quotes. It is SQLSTATE 42704, and the name in the quotes tells you which of five causes you have: a newer dump restored into an older server (transaction_timeout), a setting that was removed (lc_collate, lc_ctype), a MySQL command (SHOW TABLES), a psql variable sent to the server (autocommit), or a name of your own that PostgreSQL has not seen yet (app.tenant_id) or that has a typo.

We reproduced each of them on PostgreSQL 16.15, 17.11 and 18.6, and for the restore case we tried every way of loading the dump and counted the rows that arrived.

What does “unrecognized configuration parameter” mean?

PostgreSQL raises it when a SET, a SHOW, current_setting() or a line in postgresql.conf names a setting the server does not have. The server does not suggest a correct name: SET statment_timeout = '5s' on 17.11 returned only unrecognized configuration parameter "statment_timeout", with no hint, and the same on 16 and 18. Names with a dot behave differently: SET accepts almost any two-part name, so app.tenant_id only fails when you read it before it has a value in your session, from a SET, set_config() or a default such as ALTER DATABASE … SET.

Which name is between the quotes, and what to do about it

What does the error say after unrecognized configuration parameter?

  • "transaction_timeout"A dump from pg_dump 17 or newer, loaded into 16 or olderPlain psql and plain pg_restore report it and carry on; the data arrives. With --single-transaction, ON_ERROR_STOP or --exit-on-error nothing arrives; delete the line from the dump.
  • "lc_collate" or "lc_ctype"Removed in PostgreSQL 16Read datcollate and datctype from pg_database instead.
  • "tables", "databases", "schema"A MySQL commandSHOW in PostgreSQL only reads settings. Use \dt, \l and \dn in psql, or information_schema.
  • "autocommit"A psql variable, not a server setting\set AUTOCOMMIT off in psql. In an application, autocommit is a driver or connection setting, not a SET.
  • Your own name, like "app.tenant_id"Read before it was set in this sessionUse current_setting('app.tenant_id', true), which returns NULL. A name without a dot cannot be set at all.
  • A name that looks almost rightA typoPostgreSQL does not suggest the right name. Look it up in pg_settings.

Every branch reproduced on PostgreSQL 16.15, 17.11 and 18.6, except transaction_timeout, which only fails on 16: 17 and 18 have the setting.

unrecognized configuration parameter “transaction_timeout” when restoring a dump

transaction_timeout arrived in PostgreSQL 17 (“Add server variable transaction_timeout to restrict the duration of transactions”, in the release notes), and pg_dump 17 writes SET transaction_timeout = 0; near the top of the dump: it did in every dump we made, plain and custom format, on a database that never used the setting. Line 13 of our plain-text dump from 17.11 was that line; a dump from pg_dump 18.6 had exactly the same set of SET lines. PostgreSQL 16 does not know the setting, so it rejects the line. The 18.6 dump loaded into 17 without an error.

What happens next depends on how you restore. We loaded the same 17.11 dump of a small table (3 rows) into a 16.15 server in each way:

How the dump was loaded into PostgreSQL 16Error on transaction_timeoutRows that arrivedExit code
psql -f dump.sql (plain format)yes, then carries on3 of 30
psql -v ON_ERROR_STOP=1yes, stopsnone: the table does not exist3
psql --single-transactionyes, then 12× current transaction is abortednone0
pg_restore 17 (custom format)yes: errors ignored on restore: 13 of 31
pg_restore --exit-on-erroryes, stopsnone1
pg_restore --single-transactionyes, stopsnone1
pg_restore 16 on the custom-format fileunsupported version (1.16) in file headernone1
plain dump with the line deleted, psql -v ON_ERROR_STOP=1no3 of 30

Two of those deserve a warning. psql --single-transaction without ON_ERROR_STOP exited with 0 and restored nothing: a script that checks only the exit code reports success. And the plain pg_restore that did restore everything exited with 1, so a script that checks the exit code reports a failure for a complete restore. In parallel mode (pg_restore -j 4, four tables of 100,000 rows) the error was printed six times (Tom Lane: “you will see this error per-worker”), and the summary said errors ignored on restore: 2. All 400,000 rows arrived.

Tom Lane described the same thing on the pgsql-general list in September 2025: the error is “expected since v12 didn’t have transaction_timeout”, and “This means you can’t use —single-transaction, but it should work otherwise as long as you’re not using DDL features v12 didn’t have.”

The fix. The cleanest fix is a pg_dump of the same major version as the server you restore into. When you only have the newer dump, a plain-text dump can be edited: sed '/^SET transaction_timeout/d' dump.sql > dump-16.sql removed the one line, and the result loaded into 16 with ON_ERROR_STOP=1 and all rows. For a custom-format dump, pg_restore -f dump.sql dump.custom writes the same SQL to a file; with the line removed, it loaded into 16 with all 3 rows. The pg_dump documentation is clear that this is your problem, not a bug: “it is not guaranteed that pg_dump’s output can be loaded into a server of an older major version … Loading a dump file into an older server may require manual editing of the dump file to remove syntax not understood by the older server.”

Restoring one tenant’s data with pg_dump under row-level security has its own errors; those are in pg_dump for one tenant.

transaction_timeout in postgresql.conf on an older server

The same line in postgresql.conf behaves differently. We added transaction_timeout = 0 to the configuration of a 16.15 server. A reload (select pg_reload_conf()) logged unrecognized configuration parameter "transaction_timeout" in file "…/postgresql.conf" line 829 and configuration file … contains errors; no changes were applied — so the reload applied none of the other changes in the file either, and only the log said so. pg_file_settings showed the line with applied = f and the error. A restart was worse: the server stopped with FATAL: configuration file "…/postgresql.conf" contains errors and did not come back. A postgresql.conf from a 17 server in which transaction_timeout was uncommented is enough to cause it; in the default file of 17 and 18 the line is commented out.

unrecognized configuration parameter “lc_collate” or “lc_ctype”

SHOW lc_collate; and SHOW lc_ctype; failed on 16.15, 17.11 and 18.6. PostgreSQL 16 removed both; the release notes say “Collations and locales can vary between databases so having them as read-only server variables was unhelpful.” Tools written for 15 or older may still ask for them. The value is in the catalog:

select datcollate, datctype, datlocprovider
from pg_database
where datname = current_database();

On all three versions that returned en_US.utf8, en_US.utf8 and the provider.

unrecognized configuration parameter “tables”, “databases” or “schema”

SHOW TABLES;, SHOW DATABASES;, SHOW SCHEMA; and SHOW SCHEMAS; each returned unrecognized configuration parameter with the word after SHOW: in PostgreSQL, SHOW reads a setting and nothing else. The equivalents that worked:

MySQLpsqlSQL
SHOW TABLES\dtselect table_schema, table_name from information_schema.tables where table_schema not in ('pg_catalog', 'information_schema')
SHOW DATABASES\lselect datname from pg_database where not datistemplate
SHOW SCHEMAS\dnselect schema_name from information_schema.schemata

unrecognized configuration parameter “autocommit”

SET autocommit = off; failed on 17.11. Autocommit is not a server setting in PostgreSQL: it is something the client does. In psql it is the variable \set AUTOCOMMIT off (upper case, with a backslash). After that, an INSERT left the session in an open transaction, and a rollback removed the row; with the default on, the same rollback only warned there is no transaction in progress and the row stayed. In an application, it is a switch on the driver or the connection, not a SET.

unrecognized configuration parameter for your own setting, like “app.tenant_id”

This is the one multi-tenant applications meet, because the usual way to give row-level security its tenant is a custom setting. In a fresh session SHOW app.tenant_id; and select current_setting('app.tenant_id'); both failed with unrecognized configuration parameter "app.tenant_id". current_setting('app.tenant_id', true) returned NULL instead of an error. After SET app.tenant_id = '5' both worked.

Three details we measured:

  • The name needs a dot. SET tenant_id = 5 failed with unrecognized configuration parameter "tenant_id". The documentation explains why: PostgreSQL “will accept a setting for any two-part parameter name”, treated as a placeholder.
  • After a RESET, it is no longer unknown. In the same session, SET followed by RESET left an empty string, not NULL and not the error. A policy that casts it to a number then fails in a different way: invalid input syntax for type integer: "". What current_setting returns in each state, and how a policy should read it, is in current_setting and set_config in PostgreSQL.
  • A default per database is per database. After ALTER DATABASE postgres SET app.tenant_id = '0', a new session in postgres showed 0; a session in another database still got the error.

What we did not measure

Old psql binaries reading a dump from a newer pg_dump; our psql and pg_restore were the current minor releases of each version. Managed services that set their own parameters. Extensions whose settings only exist once the library is loaded, such as pg_stat_statements.* before shared_preload_libraries includes it.

Sources: PostgreSQL documentation on client connection defaults (transaction_timeout, absent from the 16 version), customized options and pg_dump; release notes for PostgreSQL 17 and PostgreSQL 16; Tom Lane on pgsql-general, 26 September 2025. All read on 16 October 2026. All measurements are our own, on PostgreSQL 16.15, 17.11 and 18.6 in containers, on 16 October 2026.

Let's talk

What are we building?

One conversation is enough to know whether we fit. Tell us what you have in mind — we will tell you how fast it can happen, and whether we are the right people for it.

Start the conversation