Why PostgreSQL 17 must be in place before GitLab 19
If your self-managed GitLab runs on an older PostgreSQL, the database upgrade is not a side task you can fold into a GitLab minor update. PostgreSQL 17 has to be in place before you move to GitLab 19, and the GitLab side of that move still follows the required upgrade stops, including the 18.11 stop before 19.0. Plan the two tracks together: the GitLab hops set the order, and the database step sets a prerequisite that must be finished on the path to 19.0.
The database change is a major PostgreSQL upgrade, which is a different kind of work from a GitLab minor release. PostgreSQL keeps the internal storage format stable within a major version, so moving between majors means dumping and restoring, running pg_upgrade, or setting up logical replication. That is why the database step falls outside the zero-downtime procedure GitLab documents for multi-node instances. Expect a planned maintenance window for the cutover, and confirm with your GitLab release notes exactly which PostgreSQL floor applies to the version you are targeting.
Check where you stand against the PostgreSQL support window before you schedule anything. The supported majors are 14 (to November 12, 2026), 15 (to November 11, 2027), 16 (to November 9, 2028), 17 (to November 8, 2029) and 18 (to November 14, 2030), and versions 13 and earlier are unsupported. An instance still on 14 or 15 has a support end date that may arrive during your migration, which is a useful argument for doing the upgrade now. Confirm your current version, whether the database is bundled or external, and your rollback point before you commit to a date.
What changes in the database layer and what to do about it
This table lists the database changes that affect a move to PostgreSQL 17 before GitLab 19.0, with the impact of each and the action to take. Read it in order: confirm the version requirement and your deployment type first, then plan the storage format change and the authentication work. The main takeaway is that a major PostgreSQL upgrade needs its own maintenance window and a tested backup, separate from the zero-downtime GitLab procedure.
| Change | Impact | Action needed |
|---|---|---|
| PostgreSQL 17 requirement for GitLab 19.0 | GitLab 19.0 requires PostgreSQL 17, so any instance on an older database version must move before the 19.0 step. | Confirm the minimum version in the GitLab 19 upgrade documentation and schedule the database move before the 18.11 stop. |
| Bundled PostgreSQL (Linux package) | The Linux package bundles PostgreSQL, so the database version is tied to the GitLab package and its documented procedure. | Follow GitLab's documented procedure for the bundled database and take a backup before starting. |
| External PostgreSQL cluster | GitLab connects to the cluster but does not upgrade it, so your team owns the version, replicas and failover tooling. | Inventory every external database, agree the window with its owner, and test the upgrade on a staging copy. |
| Storage format on major upgrades | Minor releases keep the storage format, but a major upgrade changes it and needs dump and restore, pg_upgrade or logical replication. | Choose the method with your DBA and test the restore on a copy of production data before the window. |
| Downtime and zero-downtime procedure | Major PostgreSQL upgrades fall outside the zero-downtime GitLab procedure, so the database step needs a planned window. | Agree the window with stakeholders. If a short cutover is needed, measure logical replication timing in staging. |
| PostgreSQL support window | PostgreSQL 17 is supported until November 8, 2029, and PostgreSQL 14 ends November 12, 2026. | Record PostgreSQL 18 (final release November 14, 2030) as the next major version to plan, and retire any version nearing end of support. |
| MD5 to SCRAM password authentication | PostgreSQL 18 deprecates MD5 password authentication in favor of SCRAM, so MD5 entries will block the next major move. | Check pg_hba.conf and password_encryption for MD5 entries now, and move client roles to SCRAM before PostgreSQL 18. |
| Backups as the rollback path | A major upgrade changes the data files, so restoring from a tested backup is the main rollback option. | Take a GitLab backup and a database backup, and confirm restore steps in the GitLab backup and restore documentation. |
How to prepare the database before the upgrade window
The database work happens before the window opens, and each item below is something your team confirms in its own environment. Together they decide whether a rollback is a restore you have rehearsed or a guess, and whether the cutover can run within the time you have agreed.
Confirm a restorable backup
Take a full GitLab backup with the backup task and a separate logical dump of the PostgreSQL database, then confirm both can be restored. The GitLab backup covers repositories, uploads and database content, but it does not replace database-level recovery, so check whether your environment also needs point-in-time recovery from archived WAL. Record who can perform a restore and how long it took on a non-production copy.
Decide your point-in-time recovery
Confirm whether continuous archiving is already running and whether it covers the database that GitLab uses. If it is not, decide whether the window requires it or whether a verified full backup and a rollback plan are sufficient for your risk tolerance. Document the recovery target you can accept, because a major upgrade changes the data directory and rollback after the cutover depends on that choice.
Inventory extensions and custom objects
List every installed extension, custom function, trigger, foreign data wrapper, custom collation and non-default configuration parameter in the GitLab database. Confirm that each one has a PostgreSQL 17 build or a documented replacement, and that the owner of each object is still present. Objects that the upgrade method does not carry over must be recreated before the cutover, so note them in the runbook.
Build a restorable test environment
Restore a recent backup into a separate PostgreSQL 17 instance that matches your production hardware class, network and authentication settings. Run GitLab's upgrade steps against that copy, time the migrations and check that the application starts. Use the timings to size the maintenance window, because a copy with less data or slower storage will understate the real duration.
Confirm connection pooling settings
If PgBouncer or another pooler sits between GitLab and PostgreSQL, confirm how it routes connections during the switch to the new server, which pool mode is configured and how long existing client sessions are allowed to remain open. Check that the pooler is not pointing at the old server after cutover. Record the settings you will change and the ones you will restore if you roll back.
Verify authentication for the new server
Confirm how GitLab and any administrators connect to the database, including password and certificate settings. PostgreSQL 18 deprecates MD5 password authentication in favor of SCRAM, so any MD5 entries in your configuration should be reviewed before you move to newer versions. Test each connection method on the PostgreSQL 17 instance before the window so that a failed login does not become a cutover delay.
How the bundled and external PostgreSQL paths differ
The first decision in a PostgreSQL 17 upgrade is who owns the database host, because that determines who runs the major upgrade and who carries the outage. With the Linux package, the bundled PostgreSQL is installed and managed by the same gitlab-ctl tooling as the rest of GitLab, so the GitLab team's packaged procedure covers the database binaries and data directory on the same server. With an external cluster, the database lives on hosts your database team operates, possibly on managed services, and GitLab only holds a connection definition in gitlab.rb. The upgrade then becomes a database change that your DBA owns, with GitLab's side limited to pointing at the new version and running migrations. Confirm which path you are on before scheduling anything, because the runbook, the backup responsibility and the approval chain all follow from it.
Replication topology is where the two paths diverge most. A single bundled node has no standby unless you build one, and the GitLab Linux package documentation describes the bundled database as the simplest option rather than a high availability design. Reference architectures for larger instances, which the GitLab docs generally recommend for 3,000 or more users, use PostgreSQL with Patroni, alongside Redis Sentinel and Consul. In that topology Patroni manages leader election and failover of the PostgreSQL nodes, and the database is a cluster that must be upgraded as a whole. Ask your team which cluster tooling is in place, who can authorize a failover during the upgrade window, and whether replicas must be rebuilt or resynchronized after the new major version is in service.
GitLab's reference architectures do not support running stateful components such as PostgreSQL and Redis inside Kubernetes. The documented Cloud Native Hybrid pattern keeps stateless GitLab services on Kubernetes and places stateful services on virtual machines or managed services. The practical consequence for this upgrade is that a Helm-based GitLab instance still needs a database outside the cluster for a supported design, so the PostgreSQL 17 target is set on that external platform rather than inside the chart. Confirm with GitLab's current reference architecture page that your topology matches a documented pattern, and plan the database host, storage and backup ownership before choosing a major upgrade method.
The upgrade sequence for the PostgreSQL 17 move
This sequence moves the GitLab database to PostgreSQL 17 as a planned, separate outage, with a checkpoint and a rollback point at each stage, so GitLab 19.0 starts on a database version it supports.
Confirm current GitLab and PostgreSQL versions
Record the running GitLab version, the bundled or external PostgreSQL major version, and the GitLab release line you will move through before 19.0. Check the GitLab upgrade paths documentation for the required stops that still apply to your instance. Confirm the PostgreSQL version against the GitLab requirements for the target release, and confirm whether the database is the bundled instance or an external cluster, because the procedure differs. The checkpoint is a written inventory signed off by the database and GitLab owners.
Take and verify backups before any change
Create a GitLab backup with the backup task and copy the database dump, configuration files including gitlab.rb and the secrets file, and any object storage references to storage outside the database host. Restore the backup to a separate test host and confirm that GitLab starts and that projects, users and pipelines load. The checkpoint is a restore test with a recorded result. Until that test passes, the backup is not a rollback point. Ask your team to confirm the backup and restore steps for your install method in the GitLab backup and restore documentation.
Stop writes and enter maintenance mode
Enable maintenance mode in GitLab and stop Sidekiq, Puma and any runners or integrations that write to the database, so no new data arrives during the database move. Confirm that no background jobs are running and that the database has no active write sessions. The checkpoint is a quiet database with no application connections except the operator session. This is the start of the outage window, and the major upgrade has its own downtime that is separate from any zero-downtime procedure for GitLab itself.
Perform the major upgrade with the chosen method
Run the PostgreSQL 17 upgrade using pg_upgrade, a dump and restore with pg_dumpall, or logical replication, based on your data size, outage tolerance and the environment. Pick the method in advance and test it on a copy of the data. Pg_upgrade needs both old and new binaries installed, so confirm the packages are present. Logical replication can shorten downtime, but it needs a tested cutover. The checkpoint is a PostgreSQL 17 server that reports the expected version, starts cleanly and passes row count and extension checks. Before cutover, keep the old data directory intact as the rollback point.
Verify GitLab connects and migrations run
Point GitLab at the upgraded database, confirm the connection settings in gitlab.rb, and start GitLab services while still in maintenance mode. Run the database migration tasks for the current GitLab version and review their output for errors. Confirm that the web interface, a Git clone, a test pipeline and a Sidekiq job complete successfully. The checkpoint is a clean application health check and a test project that works end to end. If checks fail, stop, return to the old data directory and restart the previous PostgreSQL version, since the old data is still the rollback point.
Exit maintenance mode and monitor
Disable maintenance mode after the checks pass and restore runners and integrations in a controlled order. Watch logs, error rates and database connections for a period your team defines in its change plan. Keep the old data directory and the verified backup until the team signs off that the upgraded database is stable. The checkpoint is a signed change record that states the new PostgreSQL version and the date the old copy can be removed. Confirm the retention period for the old copy with your own change process.
Continue the required GitLab upgrade stops
Resume the GitLab upgrade path from the current version through each required upgrade stop, one step at a time, with the PostgreSQL 17 database in place. Check background migrations between stops before moving to the next one, and take a fresh backup at each stop. The checkpoint at each stop is a healthy instance and a finished set of migrations. The PostgreSQL 17 move does not replace these stops, and the GitLab 19.0 upgrade begins only after the path reaches the required release.
Choosing between dump and restore, pg_upgrade and logical replication
Dump and restore uses pg_dumpall to export the cluster and load it into a fresh cluster running the new major version. It is the simplest method to reason about, because the output is a logical copy that does not depend on the old on-disk format. Its cost is time: the database is unavailable for writes from the start of the dump until the restore finishes and the application is pointed at the new cluster, so the window grows with data volume.
- Best fit: small to moderate databases where a planned outage is acceptable and the team wants the fewest moving parts.
- Downtime: the full dump, load and index rebuild time, so ask the team to measure a rehearsal on a copy of production data.
- Failure handling: a failed restore is recovered by reloading into a new cluster, so keep the original cluster untouched until verification passes.
- Planner statistics: statistics are not carried over in the same way, so plan an
ANALYZEpass before reopening GitLab. - Effort: mostly scripted work, with a rollback plan defined in advance.
Before choosing this method, confirm the dump and restore steps and the statistics handling against the PostgreSQL upgrade documentation for your exact source and target versions.
pg_upgrade converts the existing data directory to the new major version in place, which avoids a full export and reload. It is usually the practical choice for larger databases where a restore would run for too long. PostgreSQL 18 adds features that matter for planning: pg_upgrade retains planner statistics across major upgrades, and it adds parallel jobs and a --swap option. The gain is shorter downtime and fewer post-upgrade steps, but the old and new binaries must both be installed, and the procedure needs careful preparation.
- Best fit: large databases where the outage must be shorter than a dump and restore, and where the team can install both major versions on the database host.
- Retained statistics: on PostgreSQL 18 target versions, planner statistics survive the upgrade, which reduces the slow period right after reopening.
- Parallel jobs: the parallel option shortens the conversion step on hosts with spare CPU and I/O capacity.
- Swap option:
--swapavoids copying or linking data files in some configurations, so check its requirements in the documentation. - Rollback: the old cluster must be kept intact until the new one is verified, which constrains disk space.
Confirm which pg_upgrade options and statistics behavior apply to your source and target versions in the PostgreSQL upgrade documentation before you rehearse.
Logical replication copies data changes from the old cluster to a new cluster running the target major version, then switches the application over. PostgreSQL documents that it works between different major versions, which allows a major upgrade with only several seconds of downtime. The trade-off is setup and operational work: publications and subscriptions must be configured, the schema and sequences need attention, and the team must watch replication lag and confirm the copy is consistent before cutover.
- Best fit: large or write-heavy databases where even a pg_upgrade outage is too long and the team has time to build and monitor replication.
- Downtime: several seconds at cutover, according to the PostgreSQL upgrade documentation, provided lag is near zero when the switch happens.
- Extra setup: publication and subscription configuration, network access between clusters, and a tested cutover runbook.
- Prerequisites to verify: how sequences, DDL and large objects are handled, since logical replication does not replicate every object type automatically.
- Ongoing load: replication adds work on the source, so measure its effect during the sync period.
Validate the replication limits and cutover steps against the PostgreSQL upgrade documentation before committing to this method for a GitLab database.
The method decision rests on four questions: how large the GitLab database is, how long a write outage the business will accept, whether the team can run replication without an outage risk, and how much disk and host capacity is available for a parallel cluster. Smaller databases with generous windows usually favor dump and restore for simplicity. Larger databases with a fixed window usually favor pg_upgrade. Logical replication fits when the window is tighter than pg_upgrade allows and the team has the skills to run it.
- Database size: measure the actual size of the GitLab database, since this drives every timing estimate.
- Outage tolerance: agree the maximum write outage with the business before choosing.
- Capacity: check free disk for a second cluster or a retained old cluster, and CPU for parallel jobs.
- Team skills: replication cutover needs practiced steps that a simple restore does not.
- Rehearsal: time each candidate on a copy of production data before choosing.
Before finalizing, confirm the chosen method and its prerequisites against the PostgreSQL upgrade documentation and the GitLab PostgreSQL 17 requirements for your target release.
What makes the PostgreSQL 17 upgrade longer or riskier
This table lists the factors that change how long a PostgreSQL 17 upgrade takes and how much can go wrong, with the direction each one pushes. Use it to decide which drivers apply to your instance before asking for a scope and quote. The main takeaway is that database size, replication topology and the number of GitLab nodes sharing the database matter more than the version pair itself.
| Driver | Why it matters | Direction of impact | What to confirm |
|---|---|---|---|
| Database size | Larger data sets take longer to dump and restore, or to copy during a logical replication cutover. | Larger raises duration and rollback cost | Current database size and growth since the last backup |
| Extensions and custom SQL | Extensions must exist for the target version, and custom functions or views may behave differently after the upgrade. | More extensions or custom SQL raises risk and test effort | Full list of extensions and any custom database objects |
| GitLab nodes sharing the database | Every Rails, Sidekiq and supporting node must stop using the old server in the same window and reconnect to the new one. | More nodes raise coordination effort and the chance of a stale connection | Node inventory, connection settings and pooler layout |
| Replication topology | Standbys, Patroni clusters and Geo secondaries each need matching versions or a rebuild plan. | More replicas or sites raise effort and extend the change window | Replica count, failover tooling and whether Geo is in use |
| Backup and restore speed | A restore is the fallback if the upgrade fails, so its duration sets how long a rollback takes. | Slower restores raise the cost of a failed attempt | Measured restore time on a copy of production data |
| Required upgrade stops still ahead | Each GitLab stop has its own database migrations, so an instance further behind has more steps before the PostgreSQL step is safe. | More remaining stops raise the total number of changes and checks | Current GitLab version and the stops still to pass |
| Chosen upgrade method | Dump and restore needs the longest outage, pg_upgrade is faster with more preparation, and logical replication needs the most setup. | Dump and restore is simplest but longest, logical replication is shortest but most complex | Method the team has tested and the outage window the business accepts |
Questions teams ask before upgrading GitLab's PostgreSQL database
Can the PostgreSQL 17 upgrade be done with zero downtime?
Not through the standard GitLab zero-downtime procedure, which upgrades the GitLab application one minor release at a time and does not change the database's major version. A major PostgreSQL upgrade is a separate operation. PostgreSQL's upgrade documentation describes three routes: dump and restore, pg_upgrade, and logical replication. Logical replication works between major versions and can keep the write outage to several seconds, but it adds replication setup, a cutover step and verification work. Confirm the exact steps for your version against the PostgreSQL upgrade documentation and GitLab's upgrade guidance before you commit to a maintenance window.
What drives the cost of a PostgreSQL 17 upgrade?
The main cost is the time of the people doing the work, plus any partner fees under a written scope. Cost rises with database size, the number of nodes, whether you run a bundled database or an external cluster, and whether you use a high availability setup with Patroni or a Geo secondary site. Each non-production environment you rehearse in adds effort, and so does proving that backups restore. The upgrade itself is a one-time project. Ongoing costs, such as database support, monitoring and later minor updates, recur. When you ask for a quote, request the line items: discovery, rehearsal, cutover, verification, rollback preparation and handover.
What does the upgrade need from our own team?
The work needs several roles at the same time. A PostgreSQL administrator owns the database method, cutover and rollback. A GitLab administrator confirms the upgrade order and the GitLab version path. Infrastructure staff provide the maintenance window, network access, storage capacity and backup access. An application or change owner signs off on post-upgrade checks, and a security contact reviews access and authentication settings. Your team also needs time to rehearse on a copy of production data, because the rehearsal results decide the cutover plan. Agree these responsibilities in writing before the project starts.
Can our own team do the PostgreSQL 17 upgrade themselves?
Yes, if you have people with hands-on PostgreSQL administration experience, familiarity with GitLab upgrades, and time to rehearse. The questions to answer honestly are whether the database is bundled with GitLab or runs as an external cluster, how many nodes depend on it, and whether anyone has restored a backup under time pressure. If the answer to several of these is no, a partner can plan the method, run the rehearsals, support the cutover and document the result. DeployOpen works under fixed-scope agreements with written deliverables and offers retainers for ongoing support. Either way, the GitLab upgrade stops still apply, so check the GitLab upgrade paths first.
How long does the database upgrade take?
The duration depends on drivers you can measure in your own environment, not on a standard figure. Data volume matters most, because dump and restore time grows with the amount of data. The method you choose changes the outage length: logical replication aims for a short cutover, while dump and restore needs a longer write freeze. The number of rehearsals, the size of the change window, the number of GitLab nodes that must restart, and any Geo sites also add time. Ask for a timed rehearsal on a copy of production, then use those measurements to plan the window and the schedule. Treat any duration in a proposal as a claim to test against that rehearsal.
What does a rollback look like after a failed PostgreSQL upgrade?
Rollback depends on the method and the point of failure. Before cutover, the simplest path is to keep the application pointed at the original database and stop the attempt. After cutover, you need a verified backup taken immediately before the change, and a tested procedure to restore it and point GitLab back at it. With logical replication, the source database can remain in place until you confirm the new one, which can make a return easier, but any writes made after cutover must be reconciled. Restore time grows with data size. Confirm the procedure against the GitLab backup and restore documentation and the PostgreSQL upgrade guide, and rehearse the rollback as well as the upgrade.
How long will PostgreSQL 17 receive support?
PostgreSQL 17 is supported until November 8, 2029, according to the PostgreSQL versioning policy. Support windows for the other supported releases differ: PostgreSQL 14 is supported until November 12, 2026, and PostgreSQL 15 until November 11, 2027. PostgreSQL 18 was first released on September 25, 2025, and is supported until November 14, 2030. If you run an older release today, the support end date is the main planning constraint. It determines how long you can delay the upgrade, and it helps you decide whether to target PostgreSQL 17 alone or to plan for a later major version as well. Confirm which release your GitLab version requires before choosing a target.
Does PostgreSQL high availability need to be in place first?
It is not a strict prerequisite for a single-node upgrade, but it changes how you plan the cutover. PostgreSQL supports hot standby servers, synchronous and asynchronous replication, but it does not detect a failed primary or promote a standby by itself. Automatic failover needs external tools. GitLab's reference architectures recommend a high availability strategy for 3,000 or more users, and that design uses PostgreSQL with Patroni. Before you upgrade, confirm which node is primary, how failover is handled, and whether standbys must be upgraded or rebuilt afterward. Check the PostgreSQL high availability documentation and GitLab's reference architecture guidance for your user count.
How DeployOpen scopes and delivers the PostgreSQL 17 upgrade
DeployOpen delivers the PostgreSQL 17 step under a written, fixed scope agreed before work starts. The scope states which database is in play, whether it is the database bundled with the Linux package or an external PostgreSQL cluster, which GitLab version sits at each stop, and which environments are covered. It also names the deliverables, such as the rehearsal report, the runbook and the rollback record. Because the work runs inside your own cloud accounts, data centers or air-gapped network, the database, its backups and the test copies never leave infrastructure you control. Pricing follows from that written scope, so the questions to bring to a quote are which GitLab stops are included, how many environments need a rehearsal, and whether the external cluster's tooling is in scope.
The database step is planned together with the GitLab upgrade path rather than as a separate task. DeployOpen maps the current PostgreSQL version against the target GitLab release using the GitLab upgrade paths documentation, then sets the order of the PostgreSQL move relative to the required upgrade stops. Before any change, the team prepares a verified backup, confirms the GitLab backup and restore procedure works in a test environment built from a recent copy of production, and records the replication and high availability topology so the upgrade method, whether pg_upgrade or logical replication, is chosen for the actual cluster. Your team should confirm the exact PostgreSQL floor required by the target GitLab release in the release notes before the scope is signed.
Delivery ends with rehearsed rollback, not just a successful forward run. DeployOpen runs upgrade rehearsals against the test copy and times the cutover window with your operations staff, then runs a rollback drill that restores the pre-upgrade backup and confirms GitLab starts cleanly against it. Ongoing needs, such as the later PostgreSQL minor releases, the next GitLab stop and monitoring of the database after cutover, can be covered by a retainer, so the knowledge built during this work stays with your team. Ask any provider whether the rollback drill, the backup verification and the post-cutover checks are written into the fixed scope or left to be negotiated later.

