
You start a vCenter upgrade, watch the progress, and hope this will be one of those maintenance windows where everything finishes on time.
Then the database upgrade fails.
That is what I ran into while upgrading VMware vCenter Server to 9.1.0.0300. The blocker was an orphaned record in the vCenter database, sitting right where the upgrade needed to enforce a foreign key relationship.
The fix was short. Understanding why it was the right fix mattered considerably more.
Here is the error, what it meant, and the cleanup used in this case.
The error that stopped the upgrade
The useful detail appeared in vcdb_inplace.err:
Error while executing ./Upgrade-v2017-to-v2018/postgresql/upgrade_PostgreSQL.sql,
reason: Statement failure(rc=-1).
1 23503 ERROR: insert or update on table "vpx_host_crypto_tag_keys"
violates foreign key constraint "fk_vpx_host_crypto_tag_keys"
DETAIL: Key (key_id)=(1226) is not present in table "vpx_host_crypto_keys".
That last line is where the investigation becomes useful. PostgreSQL is telling us which relationship is broken, right down to the missing key ID.
The 1226 value is a database identifier from the supplied error, not an IP address or hostname. Other affected environments may report a different value.
Broadcom documents this exact failure in KB 453471, including the log location /var/log/vmware/vpxd/vcdb_inplace.err.
What was actually wrong?
Two tables were involved:
| Table | Relationship involved in this failure |
|---|---|
vc.vpx_host_crypto_tag_keys | Contains the key_id references being checked |
vc.vpx_host_crypto_keys | Must contain the corresponding referenced keys |
During the schema migration, the upgrade attempted to enforce the constraint fk_vpx_host_crypto_tag_keys.
In plain English: if a tag-key record references a key, that key must exist in the corresponding keys table.
In this case, a record referenced key_id = 1226, but the matching entry was missing. That left an orphaned reference, which prevented the constraint from being applied and stopped the upgrade.
The error explains the inconsistency. It does not explain when the record became orphaned or what originally caused it. There is no reason to invent that part of the story.
Before touching the database
This is a direct change to VCDB. A short SQL statement still deserves a proper recovery plan.
The starting point for this procedure is a clean, pre-upgrade source vCenter, with a valid backup or an offline snapshot taken before the database change. Follow the recovery procedure appropriate to the failed upgrade rather than assuming the failed attempt left the appliance ready for another run.
For Enhanced Linked Mode environments, account for the entire replication group when planning recovery. Broadcom’s related database-upgrade guidance calls for powered-off snapshots of all ELM member nodes.
Broadcom KB 453471 explicitly directs customers to Support for deleting the orphaned records. The SQL below records the remediation supplied for this case; have Support confirm that it applies to your database before using it elsewhere.
Step 1: Connect to the source appliance
SSH to the source VCSA as root. Here is an anonymised example:
ssh root@vcenter01.angrysysops.com
If you land in the appliance shell, enter the Bash shell using:
shell
Then connect to the embedded PostgreSQL database:
/opt/vmware/vpostgres/current/bin/psql -U postgres -d VCDB
You should reach the database prompt:
VCDB=#

Step 2: Inspect the records first
Before running the cleanup, use a read-only query to inspect the rows matching its condition:
SELECT *
FROM vc.vpx_host_crypto_tag_keys
WHERE key_id NOT IN (
SELECT key_id
FROM vc.vpx_host_crypto_keys
);
This uses the same selection condition as the deletion below, allowing you to review what that statement would target.
If the results do not match the failure you are investigating, pause and reconcile the logs and database state with Support. Do not broaden the deletion just to make the installer move forward.
Step 3: Apply the case-specific cleanup
With the recovery point in place and the affected records confirmed, the remediation supplied for this case was:
DELETE FROM vc.vpx_host_crypto_tag_keys
WHERE key_id NOT IN (
SELECT key_id
FROM vc.vpx_host_crypto_keys
);
The statement removes tag-key rows matching that orphaned-reference condition. It does not create replacement crypto keys or restore missing key material.
Also, notice that it is not limited to key ID 1226. It targets every row matching the condition, which is why checking the result set first matters.
PostgreSQL reports how many rows were deleted. For example:
DELETE 1
Your count may differ. That output confirms the deletion count; it does not certify the health of the entire database.
With the normal psql autocommit behaviour, this standalone deletion commits immediately. Exiting the session will not undo it.
Step 4: Check the result and retry
Run the read-only query again. After the cleanup, it should return no rows matching the deletion condition.
Exit PostgreSQL:
\q
Then retry the vCenter upgrade through the appropriate workflow for your environment.
Removing these orphaned references addresses this particular constraint failure. It cannot guarantee that a later upgrade stage will not uncover something else. If another error appears, investigate that error rather than repeating the cleanup automatically.
Verify more than the version number
Once the upgrade completes, confirm that:
- The upgrade reports success and vCenter shows 9.1.0.0300.
- The vSphere Client is accessible and the expected inventory is present.
- Hosts reconnect and the services expected for your deployment are running.
- The upgrade logs no longer report this foreign key constraint failure.
- Relevant encryption or key-provider checks show no new issues.
A successful SQL command is one checkpoint. A healthy, upgraded vCenter is the actual goal.
Angry Admin verdict
The frustrating part of this failure was how small the underlying inconsistency was compared with the operation it stopped.
One missing key reference was enough to bring the database migration to a halt.
The useful lesson is to read the specific PostgreSQL error before trying another upgrade. Here, it named both tables, the constraint, and the key that failed validation. That is a much better starting point than staring at a failed progress bar and hoping the next attempt feels more cooperative.
Find the offending reference. Protect your recovery path. Confirm the cleanup. Then retry.
vCenter maintenance windows already have enough surprises without adding improvised database surgery.