INITDB(1)

๐Ÿ’– initdb โ€” the PostgreSQL glow-up tool ๐Ÿ’–

PostgreSQL 18.6 Documentation ยท INITDB(1) ยท she's giving database-cluster-birth energy โœจ


๐ŸŒธ NAME ๐ŸŒธ

initdb โ€” create a new PostgreSQL database cluster. bestie, this is literally where every single Postgres era begins ๐Ÿซถ


โœจ SYNOPSIS โœจ

initdb [option...] [--pgdata | -D] directory

that's it. that's the whole vibe. options go in, a directory goes at the end, and a whole cluster pops out ๐Ÿ’…


๐Ÿฆ‹ DESCRIPTION ๐Ÿฆ‹

okay so initdb creates a new PostgreSQL database cluster. that's the whole mission statement. no cap.

Creating a database cluster consists of a few iconic little steps: creating the directories in which the cluster data will live, generating the shared catalog tables (these are the tables that belong to the whole cluster rather than to any particular database), and creating the postgres, template1, and template0 databases.

Now let's talk about the girlies in that trio:

  • postgres โ€” a default database meant for use by users, utilities and third party applications. she's the main character ๐Ÿ‘‘
  • template1 and template0 โ€” meant as source databases to be copied by later CREATE DATABASE commands. they're the blueprints, the patterns, the ~originals~.
๐Ÿšจ template0 should never be modified ๐Ÿšจ but you can add objects to template1, which by default will be copied into databases created later. See Section 22.3 for more details.

Okay, real talk about permissions for a sec ๐Ÿ™ˆ

Although initdb will attempt to create the specified data directory, it might not have permission if the parent directory of the desired data directory is root-owned. to initialize in such a setup, the move is:

  1. create an empty data directory as root
  2. then use chown to assign ownership of that directory to the database user account
  3. then su to become the database user to run initdb

slay, problem solved ๐Ÿ’…


who is allowed to run this? the plot twist nobody expects:

initdb must be run as the user that will own the server process, because the server needs to have access to the files and directories that initdb creates. and since the server cannot be run as root, you must not run initdb as root either.

๐Ÿ’€ it will in fact refuse to do so. she said no and she meant it.

security tea โ˜• โ€” for security reasons the new cluster created by initdb will only be accessible by the cluster owner by default. the --allow-group-access option allows any user in the same group as the cluster owner to read files in the cluster. this is useful for performing backups as a non-privileged user. very "let your friends in but only your specific friends" energy ๐Ÿซถ


locale & encoding, the part everyone skips and then regrets ๐Ÿ˜ญ

initdb initializes the database cluster's default locale and character set encoding. these can also be set separately for each database when it is created. initdb determines those settings for the template databases, which will serve as the default for all other databases.

By default, initdb uses the locale provider libc (see Section 23.1.4). the libc locale provider takes the locale settings from the environment, and determines the encoding from the locale settings.

To choose a different locale for the cluster, use the option --locale. there are also individual options --lc-* and --icu-locale (see below) to set values for the individual locale categories.

โš ๏ธ note that inconsistent settings for different locale categories can give nonsensical results, so this should be used with care. mixing and matching is not always the serve you think it is, bestie.

Alternatively, initdb can use the ICU library to provide locale services by specifying --locale-provider=icu. the server must be built with ICU support. to choose the specific ICU locale ID to apply, use the option --icu-locale.

๐Ÿงš heads up: note that for implementation reasons and to support legacy code, initdb will still select and initialize libc locale settings when the ICU locale provider is used. she's got range like that.

When initdb runs, it will print out the locale settings it has chosen. if you have complex requirements or specified multiple options, it is advisable to check that the result matches what was intended. always do the vibe check on your locale output, fr fr โœ…

More details about locale settings can be found in Section 23.1.

To alter the default encoding, use the --encoding. more details can be found in Section 23.3. ๐ŸŒˆ


to be continued, bestieโ€ฆ โœจ

โœจ OPTIONS โœจ

Okay bestie, here's the whole menu of flags ๐Ÿ’… Every single one, no skips, no shortcuts.

  • -A authmethod</b>, *--auth=authmethod* โ€” sets the default auth method for local users, and it's the one that gets written into pg_hba.conf (both the host and local lines). Wanna know what values are legal? Peep Section 20.1. initdb will pre-fill those pg_hba.conf entries using whatever method you picked, and it does that for non-replication and replication connections. ๐Ÿซถ
โš ๏ธ Do not use trust unless you genuinely trust every single local user on your system. Like, all of them. And yet โ€” trust is the default, because ease of installation said "main character energy" ๐Ÿ™ˆ
  • --auth-host=authmethod โ€” the auth method for local users coming in over TCP/IP connections; this is what lands in the host lines of pg_hba.conf.
  • --auth-local=authmethod โ€” the auth method for local users coming in over Unix-domain socket connections; this one's for the local lines of pg_hba.conf.
  • -D directory</b>, *--pgdata=directory* โ€” where your database cluster should live. It's literally the only thing initdb needs from you โ€” but you can dodge typing it by setting the PGDATA environment variable, which is lowkey convenient because the database server (postgres) can find the data directory later using that exact same variable. Iconic coordination. โœจ
  • -E encoding</b>, *--encoding=encoding* โ€” picks the encoding for the template databases. It also becomes the default encoding for every database you create afterwards, unless you override it at that point. All the character sets the PostgreSQL server supports are listed in Section 23.3.1.

By default, the template database encoding is derived from the locale. But if --no-locale is specified (or equivalently, if the locale is C or POSIX), then the default is UTF8 for the ICU provider and SQL_ASCII for the libc provider.

  • **-g</b>, **--allow-group-access*** โ€” lets users in the *same group* as the cluster owner read all the cluster files that initdb` creates. Heads up though: this option is ignored on Windows, because Windows doesn't do POSIX-style group permissions. Sorry bestie ๐Ÿ’€
  • --icu-locale=locale โ€” sets the ICU locale, for when the ICU provider is the one in use. Locale support is all explained in Section 23.1.
  • --icu-rules=rules โ€” extra collation rules to customize how the default collation behaves. ICU only, babes. ๐Ÿงš
  • **-k</b>, **--data-checksums*** โ€” puts checksums on data pages so corruption from the I/O system can't just silently vibe in the background undetected. This is **enabled by default**; use --no-data-checksums` to turn checksums off.

Fair warning: enabling checksums might cost you a small performance penalty. When it's on, checksums get calculated for all objects, in all databases, and every checksum failure gets reported in the pg_stat_database view. Section 28.2 has the details.

  • --locale=locale โ€” the default locale for the database cluster. If you don't specify it, the locale is inherited from the environment that initdb is running in. Locale support lives in Section 23.1.

And if --locale-provider is builtin, then --locale or --builtin-locale must be specified, and it has to be set to C, C.UTF-8 or PG_UNICODE_FAST.

  • --lc-collate=locale, --lc-ctype=locale, --lc-messages=locale, --lc-monetary=locale, --lc-numeric=locale, --lc-time=locale โ€” just like --locale, but each one only sets the locale in that one specific category. One category per flag, very focused, very slay. ๐Ÿ’…
  • --no-locale โ€” literally just --locale=C. Same thing, shorter to type.
  • --builtin-locale=locale โ€” the locale name to use when the builtin provider is the one doing the work. Locale support: Section 23.1.
  • *--locale-provider={builtin*|libc|icu}** โ€” sets the locale provider for databases created in the new cluster. You *can* override it later in the CREATE DATABASEcommand whenever you make new databases. Default islibc` (see Section 23.1.4).
  • --no-data-checksums โ€” do not enable data checksums. That's it, that's the whole thing.
  • --pwfile=filename โ€” makes initdb read the bootstrap superuser's password out of a file. The first line of that file is what counts as the password. ๐Ÿ”
  • -T config</b>, *--text-search-config=config* โ€” sets the default text search configuration. More info over at default_text_search_config.
  • -U username</b>, *--username=username* โ€” sets the user name of the bootstrap superuser. Defaults to the name of the operating-system user who's running initdb.
  • **-W</b>, **--pwprompt*** โ€” makes initdb` prompt you for a password to give the bootstrap superuser. If you're not planning on using password authentication, this isn't important. But otherwise? You won't be able to use password authentication until a password is set up. No password, no entry. ๐Ÿ˜ญ
  • -X directory</b>, *--waldir=directory* โ€” where the write-ahead log should be stored.
  • --wal-segsize=size โ€” sets the WAL segment size, in megabytes. This is the size of each individual file in the WAL log. Default size is 16 megabytes. The value must be a power of 2 between 1 and 1024 (megabytes). And heads up: this can only be set during initialization โ€” you cannot change it later. Periodt.

Why would you touch it? It can be useful for controlling the granularity of WAL log shipping or archiving. Also, in databases with a high volume of WAL, the sheer number of WAL files per directory can become a whole performance and management problem. Bumping up the WAL file size reduces the number of WAL files. Fewer files, fewer problems. ๐ŸŒˆ


Other, less commonly used, options are also available:

  • -c name=value</b>, *--set *name=value โ€” forcibly sets the server parameter name to value during initdb, AND installs that setting in the generated postgresql.conf file, so it'll keep applying during future server runs. You can give this option more than once to set several parameters. It's mainly useful when the environment is such that the server won't start at all using the default parameters. Emergency-mode vibes. ๐Ÿšจ
  • *-d</b>, *--debug*** โ€” prints debugging output from the bootstrap backend, plus a few other messages that the general public doesn't really care about. The bootstrap backend is the program initdb` uses to create the catalog tables. Be warned: this option generates a tremendous amount of extremely boring output. Like, astonishing amounts. ๐Ÿ’€
  • --discard-caches โ€” runs the bootstrap backend with the debug_discard_caches=1 option. This takes a very long time and is only of use for deep debugging. Deep. Like, trench-deep.
  • -L directory โ€” tells initdb where to find its input files for initializing the database cluster. Normally you don't need this. If you do need to specify their location explicitly, you'll be told. You'll know. ๐Ÿซถ
  • **-n</b>, **--no-clean*** โ€” by default, when initdb` figures out that an error stopped it from completely creating the database cluster, it removes any files it might have created before it discovered it couldn't finish the job. This option inhibits that tidying-up, which makes it useful for debugging.
  • -N</b>, *--no-sync*** โ€” by default, initdbwaits for all files to be written safely to disk. This option makesinitdb` return *without waiting โ€” which is faster, but means a subsequent operating system crash can leave your data directory **corrupt. Generally this is useful for testing, but it should not be used when creating a production installation. Please bestie, not in prod. ๐Ÿ™
  • --no-sync-data-files โ€” by default, initdb safely writes all database files to disk. This option tells initdb to skip synchronizing all files in the individual database directories, the database directories themselves, and the tablespace directories โ€” i.e., everything in the base subdirectory and any other tablespace directories. Other files, like the ones in pg_wal and pg_xact, will still be synchronized unless --no-sync is also specified.

Note that if --no-sync-data-files is used together with --sync-method=syncfs, some or all of those files and directories will get synchronized anyway, because syncfs processes entire file systems. Sneaky. ๐Ÿ˜

This option is primarily intended for internal use by tools that separately ensure the skipped files are synchronized to disk.

  • --no-instructions โ€” by default, initdb writes instructions for how to start the cluster at the end of its output. This option leaves those instructions out. Mainly intended for tools that wrap initdb in platform-specific behavior, where those instructions are likely to be wrong anyway.
  • **-s</b>, **--show*** โ€” show internal settings and exit, without doing anything else. Handy for debugging your initdb` installation. ๐Ÿ”
  • --sync-method=method โ€” when set to fsync, which is the default, initdb recursively opens and synchronizes all files in the data directory. The search for files will follow symbolic links for the WAL directory and each configured tablespace.

On Linux, syncfs may be used instead, to ask the operating system to synchronize the whole file systems containing the data directory, the WAL files, and each tablespace. Check out recovery_init_sync_method for the caveats you should know about when using syncfs.

This option has no effect when --no-sync is used.

  • **-S</b>, **--sync-only*** โ€” safely writes all database files to disk and exits. It does **none** of the normal initdboperations. Generally this is useful for ensuring reliable recovery after changingfsyncfromofftoon`.

Other options:

  • **-V</b>, **--version*** โ€” prints the initdb` version and exits.
  • **-?</b>, **--help*** โ€” shows help about initdb` command line arguments, and exits.

๐ŸŒธ ENVIRONMENT ๐ŸŒธ

  • PGDATA โ€” specifies the directory where the database cluster is to be stored; can be overridden using the -D option.
  • PG_COLOR โ€” specifies whether to use color in diagnostic messages. Possible values are always, auto and never.
  • TZ โ€” specifies the default time zone of the created database cluster. The value should be a full time zone name (see Section 8.5.3).

๐Ÿ“ NOTES ๐Ÿ“

initdb can also be invoked via pg_ctl initdb. Two doors, same room, you're welcome. ๐Ÿšชโœจ


๐Ÿ‘€ SEE ALSO ๐Ÿ‘€

pg_ctl(1), postgres(1), Section 20.1


And that's a wrap, bestie!! ๐Ÿ’– This lil masterpiece came to you courtesy of PostgreSQL 18.6, dated 2026, and it's the INITDB(1) page. Go forth and initialize something gorgeous. ๐Ÿ‘‘๐Ÿฆ‹