systemd-sysusers and Directory-Managed Postgres Accounts: Avoiding Startup Failures
Upgrading a Postgres database cluster to the next minor release is typically expected to be a low-risk routine task. However, system administrators managing Postgres deployments across various versions and flavors in enterprise environments with Active Directory (AD) or centralized LDAP directory integration may find their database instances failing to start automatically after a reboot following an upgrade, as exemplified by issues encountered in EDB Postgres Advanced Server (EPAS) 17.11.
Beginning in the autumn of 2025, RPM packages distributed by EDB and the PostgreSQL Global Development Group (PGDG) started switching to declarative user configuration relying on the systemd-sysusers program. Instead of imperatively creating system user accounts with RPM package scriptlets, the packages now install definition files, such as /usr/lib/sysusers.d/edb-as-17.conf in EPAS 17.11, which are handled by systemd-sysusers. Initially the new approach was introduced only in the Fedora-specific PGDG packages for PostgreSQL 14.19, 15.14, 16.10 and 17.6; beginning with version 18, all PGDG RPM packages adopted the new design. EDB followed suit for EPAS and EDB Postgres Extended in 17.11 and 18.2. Maintainers of other software in the PostgreSQL ecosystem are switching to this model as well: recent packages for PgBouncer and PgPool II make use of systemd-sysusers.
While intended to align packaging with modern Linux distribution standards, these declarative definitions can trigger an early-boot race condition on servers where the database system account (e.g., enterprisedb or postgres) is provisioned via central directory services (such as SSSD, Winbind, or CentrifyDC).
This post explores why this change was introduced, how the boot race condition occurs, and how to mitigate or permanently fix the issue in your environment.
Am I Affected
If, after upgrading your EDB Postgres instance to version 17.11 or 18.2, or community PostgreSQL to version 18.0 or later, you find that it fails to start automatically after the server reboot, check the startup error message. The exact error message depends on which component fails first, systemd or Postgres itself, and may differ from host to host. In general, if you see a message indicating that the data directory is missing, inaccessible, or owned by a different user, you may be affected by this change. For a definitive answer, compare the UID of the Postgres system account (e.g. getent passwd enterprisedb) with that of the owner of the Postgres data directory (ls -ldn <data directory>): if they differ, you have the problem we discuss here. Scroll down to the Solutions section of this document to see the possible fixes.
Note that you will never be affected if you only use local system accounts defined in /etc/passwd.
Background:
The Shift to Declarative User Management
Traditionally, RPM packages created service users by including imperative %pre shell scriptlets in the RPM spec file. These scriptlets called useradd or groupadd during package installation.
Modern Linux distributions (Fedora 40+, RHEL 10, openSUSE) and upstream RPM 4.19+ have moved away from shell scriptlets in favor of declarative user management powered by systemd-sysusers.
Under this model:
- Packages drop a definition file into
/usr/lib/sysusers.d/(e.g.,/usr/lib/sysusers.d/edb-as-17.conf). - The package manager or system boot process delegates account creation to
systemd-sysusers. - This ensures consistent user provisioning across container builds, immutable OS images (like OSTree/bootc), and traditional bare-metal or virtual machine deployments.
The new approach has several advantages:
- Declarative files allow package managers, system administrators, and security auditors to inspect what users/groups a package requires before installation, improving auditability.
- Administrators can override package defaults, implement their own system account management processes, and avoid installation failures when the accounts are already present on the server.
Many Postgres users have been asking for these package features, particularly the latter.
A side effect of using systemd-sysusers is that it evaluates and potentially creates missing accounts not only at the package installation time, but also upon server restart.
To keep pace with upstream packaging guidelines and address user requests, EDB is updating its software packages to provide the sysusers configuration files instead of imperative system account creation. You can determine whether a package uses the new approach by running the following command:
sudo dnf repoquery -l <package name> | grep sysusersAnatomy of the Race Condition
The addition of a sysusers.d file in a minor release can introduce breaking behavior on servers utilizing central directory services (Active Directory, FreeIPA, LDAP) due to early-boot sequence timing.
Boot
|
+-- 1. systemd-sysusers.service (early boot)
| Reads /usr/lib/sysusers.d/edb-as-17.conf
| Looks up "enterprisedb": directory daemon not running yet, user not found
| Creates a local entry in /etc/passwd (e.g. UID 987)
|
+-- 2. edb-as-17.service starts
| "enterprisedb" resolves to the local entry (UID 987)
| Data directory is owned by the AD UID (e.g. 10050)
| Startup FAILS
|
\-- 3. centrifydc.service (or sssd / winbind) becomes ready
"enterprisedb" now resolves to the AD UID (e.g. 10050)
Too late for the failed startupIf step 3 completes before step 2, the lookup returns the AD identity and the service starts normally. This is why only some hosts, and only during some boot events, are affected.
The Failure Sequence Step-by-Step
- Early Boot Execution:
systemd-sysusers.serviceruns very early during system boot, typically before network interfaces or remote directory daemons (sssd.service,centrifydc.service,winbind.service) are active. - NSS Lookup Failure:
systemd-sysusersqueries Name Service Switch (NSS) to check if theenterprisedbuser exists. Because the AD daemon is offline, NSS reports thatenterprisedbdoes not exist. - Local Account Creation: Believing the user is missing,
systemd-sysuserscreates a localenterprisedbaccount in/etc/passwdand/etc/group, assigning it the next available local system UID (e.g., 987). - Database Startup Failure: EPAS attempts to start using the local service user. The data directory on disk is owned by the AD UID (e.g., 10050). EPAS fails to launch due to access errors when attempting to read disk files.
- Directory Service Startup: The directory service client daemon starts later in the boot process, but it is too late for launching the service.
- Why a Later Restart Can Succeed: When the directory service is listed first in
/etc/nsswitch.conf(for example,passwd: centrifydc files systemd), it takes precedence over the local entry whenever it is answering. Once it is up,enterprisedbresolves to the AD UID and the service starts normally. The local entry remains in/etc/passwd, however, and is used again on any boot where PostgreSQL starts before the directory service is ready. This is why the failure is intermittent. If thefilessource is listed first, the local entry wins on every boot.
Solutions
If your organization manages the enterprisedb identity via Active Directory or LDAP, choose one of the following methods to resolve or prevent this issue.
Solution 1: Ensure Service Startup Order and NSS Lookup Priority (Recommended)
If Active Directory is the sole authority for the service accounts, such as enterprisedb, you can ensure that the central account lookup is prioritized over the local accounts even if those are present. In the NSS configuration file, /etc/nsswitch.conf, ensure that the external identity provider is listed first:
passwd: centrifydc files systemdReplace centrifydc with your specific central directory daemon service, such as sssd or winbind, if applicable. You need to also make certain that the Postgres service, which depends on the correct account precedence, starts after the Active Directory client service by adding the appropriate dependency rule in the database service drop-in file, typically /etc/systemd/system/edb-as-17.service.d/override.conf (use your actual service name if it differs):
[Unit]
After=centrifydc.service
Wants=centrifydc.serviceDepending on how the centrifydc.service unit file is composed, it may not be available immediately after it is deemed started by systemd; it is worth adding retry logic to the Postgres service drop-in file to account for the delay, for example:
[Unit]
StartLimitInterval=200
StartLimitBurst=5
[Service]
Restart=always
RestartSec=30Solution 2: Mask the Vendor sysusers.d File
If you are certain that the database service account can be reliably looked up, you can prevent systemd-sysusers from attempting to create the user locally by masking the vendor package configuration file in /usr/lib/sysusers.d/.
Systemd configuration directories honor local overrides in /etc/sysusers.d/ over vendor files in /usr/lib/sysusers.d/. Symlinking the file to /dev/null completely disables it.
# Create a symlink in /etc/sysusers.d pointing to /dev/null
sudo ln -sf /dev/null /etc/sysusers.d/edb-as-17.confNote that the sysusers file name will differ between Postgres flavors and major versions; you will find the exact file name by using ls -l /etc/sysusers.d/ | grep -i edb.
To test the fix, you can review the systemd-sysusers runtime configuration:
sudo systemd-sysusers --cat-configThis command should show which configuration file, if any, will cause the database system account to be created.
Solution 3: Explicitly Pin the UID/GID in /etc/sysusers.d/
If you require a local fallback account entry in /etc/passwd that matches your Active Directory UID/GID exactly, override the vendor file with a custom drop-in file specifying your exact AD UID and GID.
Create /etc/sysusers.d/edb-as-17.conf:
# Type Name ID GECOS Home directory Shell
u enterprisedb 10050 "EnterpriseDB Postgres Server" /var/lib/edb/as17 /bin/bash(Replace 10050 with your designated Active Directory UID/GID.)
Ensure the home directory and shell values match those supplied in the vendor-provided file.
Solution 4: Remediating an Already-Affected Host
If a host has already rebooted and created an erroneous local /etc/passwd entry, preventing Postgres from starting:
- Remove the locally created user and group:
sudo userdel enterprisedb
# The group might be already deleted by the above command
# sudo groupdel enterprisedb- Mask the sysusers configuration (as shown in Solution 2):
sudo mkdir -p /etc/sysusers.d # required if the directory doesn't exist
sudo ln -sf /dev/null /etc/sysusers.d/edb-as-17.conf- Restart your directory daemon and verify NSS lookup:
sudo systemctl restart centrifydc.service # or sssd / winbind
getent passwd enterprisedbEnsure the output displays your expected AD UID (e.g., 10050).
- Start EPAS:
sudo systemctl start edb-as-17.serviceConclusion
The adoption of sysusers.d by EDB in recent RPM packages aligns with current Linux packaging directives. However, it introduces a behaviour change that can break enterprise deployments relying on central identity providers during minor version upgrades.
If your environment is affected, applying one of the solutions above prior to upgrading will help you avoid this problem. If you are unsure how any of the suggested solutions can be used in your particular environment, please contact the EDB technical support at https://www.enterprisedb.com/support-center.
References
- Fedora Packaging Guidelines: Users and Groups
Official Fedora documentation detailing the transition from %pre RPM scriptlets to /usr/lib/sysusers.d/. - rpm.org Documentation: Native Users and Groups
Technical details on how RPM 4.19+ parses sysusers.d files and interacts with systemd. - systemd-sysusers(8) Manual Page
Specification of the drop-in file format and precedence rules (/etc/sysusers.d vs /usr/lib/sysusers.d). - EDB blog: What's new in PostgreSQL 18 RPMs
- EDB Postgres Advanced Server Documentation
Official release notes and installation guides for EPAS releases.