Hiring for this role?

Start free with this plan

Free for your first open role.

Why Hirezen?
  • Every interviewer runs the same script and marks the same signals.
  • AI drafts the write-ups, and the debrief puts every read side by side.
  • No ATS to set up first, and no bot in the call.

Database Administrator (DBA) interview questionsTechnical Interview round

A 60 min interview plan with a time-boxed script, what each question is for, and the signals to score against. Key skills: Online schema change, vacuum and replication on a live PostgreSQL 15 cluster — what Tuesday's migration locks, why autovacuum is losing on the busiest table, and what a forgotten replication slot and an asynchronous failover cost.

Opening

Who is interviewing, how the round will run, and a question to settle the candidate in. The standard opening

Tuesday's migration

18 min
What this part is for

Purpose

Runs over one page, put in front of the candidate at the start and left there for the hour; nothing is sent ahead. Build it to exactly this content, from the heading "The shipments database, Monday 09:00" to the line "`db2` runs 0.1 to 0.4 seconds behind at peak."; what follows that line is for the interviewer. PostgreSQL 15 on three virtual machines, each with one 4 TB volume for both the data directory and `pg_wal`. `db1` is the primary. `db2` is an asynchronous streaming replica that serves no queries, with `hot_standby_feedback` off; a failover manager promotes it if `db1` fails its health check for 30 seconds, and moves the service address the application uses. `db3` is an asynchronous streaming replica where analysts run reports, some for hours; `hot_standby_feedback` was turned on there in April, after long reports kept being cancelled. Both replicas stream from `db1` by its hostname, each through a physical slot on `db1` named after it. `synchronous_standby_names` is empty, `wal_level` is `logical`, `wal_log_hints` is off, data checksums are off and `max_connections` is 400; every autovacuum, timeout and replication setting not listed, and `maintenance_work_mem`, is at its default. The database is 2.5 TB. Peak is about 3,500 transactions a second, most of them reads, 09:00 to 19:00; the cluster uses about 30 million transaction IDs and writes about 140 GB of WAL a day. The application reaches `db1` through a pooler with 300 server connections. `shipments`: 190 million rows in 160 GB, plus 95 GB across 8 indexes; each row is updated 6 to 10 times while its parcel moves, about 12 million updates a day, and parcels delivered more than four months ago are archived out of it nightly, so the row count holds steady; it was 72 GB, with about as many rows, when last rebuilt in March. `carriers` has 1,400 rows, and `shipments.carrier_id` has never had a foreign key. The migration, `0412_customs.sql`, is booked for Tuesday 11:00, and the migration tool runs each file as one transaction: `ALTER TABLE shipments ADD COLUMN customs_status text NOT NULL DEFAULT 'none';` `ALTER TABLE shipments ADD COLUMN customs_ref uuid NOT NULL DEFAULT gen_random_uuid();` `CREATE INDEX shipments_customs_status_idx ON shipments (customs_status);` `ALTER TABLE shipments ADD CONSTRAINT shipments_carrier_id_fkey FOREIGN KEY (carrier_id) REFERENCES carriers (id);` `UPDATE shipments SET customs_status = 'cleared' WHERE origin_country <> destination_country AND delivered_at IS NOT NULL;` Under it: about 58 million rows match the UPDATE, and the index is for a new screen listing parcels held at customs, `WHERE customs_status = 'held'`, a few thousand at any time. Monitoring at 09:00. The oldest transaction on `db1` is pid 48211, user `billing_sync`, opened Friday 18:05 and idle in transaction since, with a transaction ID assigned and `UPDATE shipments SET billed = true WHERE id = ANY($1)` as its last statement; every other transaction is under two minutes old; on `db3`, a report has been running since 02:10. Slots on `db1`: `db2`, physical, active, no xmin, under 1 GB retained; `db3`, physical, active, xmin equal to pid 48211's transaction ID, under 1 GB retained; `warehouse_cdc`, logical, inactive since Wednesday 18:30, when the warehouse team paused its change-data-capture connector, no xmin, catalog_xmin from Wednesday, about 650 GB retained. The volume on `db1` holds 3.2 of its 4 TB. The last autovacuum of `shipments` ended Sunday 23:40 after 3 hours 50 minutes: 5.1 million dead row versions removed, 20 million "dead but not yet removable". `db2` runs 0.1 to 0.4 seconds behind at peak. Two things on the page are right and should be left alone: the `customs_status` statement, run on its own, and `db2` serving no queries with feedback off. Book 70 minutes; the candidate's questions come after the 60.

•

I'm [YOUR_NAME] and I look after the databases at [COMPANY_NAME]. This hour is about one cluster, and this page is that cluster as it stood at nine this morning. Take a few minutes with it, and read it as if you had been put on call for it today.

What this line is for

Purpose

Not scored. Makes the page a system the candidate answers for, not a quiz on PostgreSQL. If they ask about something the page does not say, give the most ordinary answer and note that they asked.

•

This is the migration the shipments team wants to run on Tuesday at 11:00. Tell me what the application sees if it runs as written, and how you would ship the same change instead.

What this question is for, and what to listen for

Purpose

Online schema change, read on a file the candidate did not write. Lock names matter less than what follows from them on this table at 11:00 on a Tuesday; the separator is seeing the transaction around the file, and the session already holding a lock, before reaching for CONCURRENTLY.

Signals to score

  • Notices the file is one transaction, so the first ALTER's ACCESS EXCLUSIVE lock on `shipments` lasts to the end
  • Spots pid 48211 holding a lock on `shipments` since Friday: the first ALTER queues behind it, and every later query behind the ALTER
  • Gives each DDL step a short `lock_timeout` and a retry, so a waiting statement gives up instead of stalling the queue
  • Says the constant default on `customs_status` is catalog-only on PostgreSQL 15 and leaves it alone
  • Says `gen_random_uuid()` is volatile, so `customs_ref` rewrites the table and its indexes, and adds the column without a default first
  • Asks what the index is for and proposes a partial index on `customs_status = 'held'`
  • Builds the index CONCURRENTLY outside a transaction, and knows a failed build leaves an invalid index to drop
  • Adds the foreign key NOT VALID and validates it separately, after looking for `carrier_id` values with no carrier
  • Turns the 58-million-row UPDATE into a batched backfill, run before the index exists and paced against replication lag and vacuum
  • Ends with an order of steps, saying which can run at 11:00 and which belong off-peak

Follow-up questions

  • `customs_status` and `customs_ref` both add a NOT NULL column with a default. Do they cost the same?
  • The first ALTER has been waiting for twenty seconds and has changed nothing. What is the API doing?
  • The new screen shows parcels held at customs. What index does it need?
  • There has never been a constraint on `carrier_id`. What do you check before adding one?
  • Which of your steps would you run at 11:00 on a Tuesday, and which not?

Same rows, twice the size

15 min
What this part is for

Purpose

Vacuum and bloat, read as MVCC rather than as settings: whether the candidate looks for what is holding back cleanup before tuning autovacuum. Query tuning has its own round; keep this one on dead rows, not on plans.

•

`shipments` has about the rows it had in March and takes 160 GB instead of 72. Using the page, tell me why autovacuum is losing, what you would change, and whether you need those 88 GB back.

What this question is for, and what to listen for

Purpose

For a candidate who knows what "dead but not yet removable" means, that log line is most of the answer. The separator is sorting the page's three possible holders of the horizon by what each can actually hold back, and saying what fixing `db3` costs the analysts.

Signals to score

  • Reads "dead but not yet removable" as something holding back the cleanup horizon, not as autovacuum running too rarely
  • Names pid 48211's open transaction as blocking cleanup database-wide since Friday, and sets `idle_in_transaction_session_timeout`
  • Ties `hot_standby_feedback` and the hours-long reports on `db3` to the growth since April, using the dates on the page
  • Names the choices for `db3` — feedback off with a longer `max_standby_streaming_delay`, a cap on report length, or a separate copy — and what each costs
  • Rules out `warehouse_cdc` as a cause of this bloat, because a logical slot holds back only the system catalogs
  • Works out that the default scale factor waits for about 38 million dead rows here, roughly three days' worth, and sets per-table thresholds
  • Gives autovacuum a higher cost limit and more memory so runs over 255 GB finish sooner, and says why each helps
  • Says plain VACUUM makes space reusable without shrinking the table, so fixing the cause stops the growth
  • Rules out VACUUM FULL on a live table and, if the space must come back, rebuilds online after the horizon is fixed and the disk has room
  • Asks which columns the 8 indexes cover, because an update that changes an indexed column cannot be HOT

Follow-up questions

  • Autovacuum ran for almost four hours on Sunday. What stopped it removing those 20 million rows?
  • `hot_standby_feedback` went on in April. What has it been doing to `db1` since?
  • Has `warehouse_cdc` got anything to do with this table?
  • With the settings as they are, how many dead rows does `shipments` collect before autovacuum starts?
  • Do you need the 88 GB back, and what would getting them back cost?

A slot nobody is reading

12 min
What this part is for

Purpose

Replication, read through what a slot retains and the disk it can fill. Failover comes next; keep this one on retention and on the decision it forces with another team.

•

The volume on `db1` is 80% full, and 650 GB of it is `pg_wal`. Tell me what is holding it, how long we have, and what you would do today — including what your fix costs the warehouse team.

What this question is for, and what to listen for

Purpose

Tests whether the candidate knows what a replication slot promises, what that costs when nobody reads from it, and whether they can make an unwelcome decision together with the team it affects. The arithmetic is on the page.

Signals to score

  • Names `warehouse_cdc` as the cause: a slot keeps every WAL segment from its `restart_lsn`, whether anything reads from it or not
  • Works out the runway — about 0.8 TB free at about 140 GB a day, under six days — and shortens it for a migration that rewrites a table
  • Knows PostgreSQL stops when it cannot write WAL, and that here that means a failover
  • Refuses to delete files from `pg_wal` or to restart the server to free space
  • Sets out the two real options — resume the connector and let it catch up, or drop the slot and re-snapshot — and what each costs
  • Knows a caught-up logical slot still holds the WAL since the oldest open transaction began, so ends 48211 first
  • Takes the choice to the warehouse team with the date the disk fills and a deadline, rather than dropping the slot unannounced or waiting indefinitely
  • Treats growing the volume as time bought, not as the fix
  • Sets `max_slot_wal_keep_size` and says its cost: a consumer or replica further behind than the cap loses its slot
  • Adds alerts on WAL retained per slot and on inactive slots, and checks that the `db2` and `db3` slots are healthy

Follow-up questions

  • Nobody has read from `warehouse_cdc` since Wednesday. Why is it still costing disk?
  • When does the volume fill, and what happens to `db1` at that moment?
  • Why not delete the oldest files in `pg_wal`?
  • What does dropping the slot cost the warehouse team, and who decides?
  • How do you make sure no slot does this again?

db1 stops answering

15 min
What this part is for

Purpose

Replication and failover again, from the other end: what a promotion leaves behind. The backup and recovery round asks about high availability in general; this reads it through one afternoon. Nothing proposed earlier has happened yet; the page still stands.

•

Monday, 14:05: `db1` stops answering. At 14:05:30 the failover manager promotes `db2` and moves the service address, and by 14:06 the application is working again. What has the business lost, what is broken that nobody has reported yet, and what do you do this afternoon?

What this question is for, and what to listen for

Purpose

A candidate who has been through a failover lists what it leaves behind before being asked — the old primary, the other replica, the slots, the commits that never arrived. One who has only configured a failover manager tends to stop at "the application is back".

Signals to score

  • Makes sure `db1` is powered off or fenced first, because a server that misses health checks may still accept writes
  • Says asynchronous replication means commits `db2` had not received are gone, and sizes them from the lag and the load
  • Knows `db2` replays all the WAL it received before accepting writes, so the loss is what it never received, not what it had not replayed
  • Finds the lost transactions in `db1`'s WAL past `db2`'s timeline switch point, if `db1`'s disk can be read, and gives the application team the window
  • Notices `db3` still follows `db1` and serves a frozen copy, and points it at `db2` with a new slot there
  • Knows `db3` can follow `db2` only if it has not gone further along `db1`'s history than `db2` did, and otherwise rebuilds it
  • Knows `warehouse_cdc` did not survive the promotion on PostgreSQL 15, so the warehouse must re-snapshot
  • Will not start `db1` as it was, and rebuilds it from `db2` because `pg_rewind` needs `wal_log_hints` or data checksums
  • Treats the cluster as having no automatic failover target until `db1` is back, and schedules the rebuild's load on `db2`
  • Puts synchronous replication to the business as a choice with a cost on every commit, rather than adopting or dismissing it

Follow-up questions

  • `db1` missed its health checks. How do you know it is not still taking writes?
  • How much did we lose, and how would you find out exactly what?
  • What is `db3` doing right now?
  • What happened to `warehouse_cdc`?
  • How do you get back to three servers, and how long will it take?

Closing

That's the cluster. What would you like to know about ours — who can run a migration against production, when we last failed over on purpose, what wakes the on-call person at night?

What this line is for

Purpose

Not scored; anything notable goes in the notes. Candidates who have carried a pager for a database tend to ask who may change production and when failover was last rehearsed.

And one thing you should hear from me rather than find in your first month: [tell the candidate one true, specific weakness in your own databases — a migration that once locked a busy table, a failover nobody has rehearsed, a replication slot nobody can account for]. Fixing it would be part of the job.

What this line is for

Purpose

A specific, current and unflattering fact about your own databases tells the candidate what the job really is, and warns one who wants a tidy estate that this is not one. Check it is still true on the day.

Their questions for you, and what happens next. The standard closing

Database Administrator (DBA) interviews — common questions

Who is this Database Administrator (DBA) interview plan for?
It is written for the interviewer, not the candidate: the hiring manager, engineer or panel member running the Technical Interview round for a Database Administrator (DBA) role. It gives you a 60 min script to follow in the conversation — 4 questions with what each one is for and the signals to score against — so you are not writing the round from scratch the night before.
What does the Technical Interview round assess?
This round is focused on: Online schema change, vacuum and replication on a live PostgreSQL 15 cluster — what Tuesday's migration locks, why autovacuum is losing on the busiest table, and what a forgotten replication slot and an asynchronous failover cost. It works through Tuesday's migration, Same rows, twice the size, A slot nobody is reading and db1 stops answering, scoring against 40 observable signals, with follow-up prompts on all 4 questions for going deeper where an answer is thin.
How is the 60 min split up?
60 min on 4 questions. The questions take in Tuesday's migration (18 min), Same rows, twice the size (15 min), A slot nobody is reading (12 min) and db1 stops answering (15 min). The timings are there so the round stays on schedule and every candidate gets the same shape of interview — which is what makes two candidates comparable afterwards.
What other rounds should I run for a Database Administrator (DBA)?

A single round does not cover a whole role. The other rounds in this library for a Database Administrator (DBA):

Hiring for this role?

Open this plan in Hirezen and make it a position in one click.

  • Every interviewer runs the same script and marks the same signals.
  • AI drafts the write-ups, and the debrief puts every read side by side.
  • No ATS to set up first, and no bot in the call.
Start free with this plan

Free for your first open role.