diff --git a/src/backend/access/heap/vacuumlazy.c b/src/backend/access/heap/vacuumlazy.c
index 1caf3ac3b36..8a328638fd3 100644
--- a/src/backend/access/heap/vacuumlazy.c
+++ b/src/backend/access/heap/vacuumlazy.c
@@ -413,7 +413,7 @@ typedef struct LVRelState
 
 	int32		wraparound_failsafe_count; /* number of emergency vacuums to prevent anti-wraparound shutdown */
 
-	ExtVacReport extVacReport;
+	PgStat_VacuumRelationCounts extVacReport;
 } LVRelState;
 
 
@@ -525,7 +525,7 @@ extvac_stats_start(Relation rel, LVExtStatCounters *counters)
  */
 static void
 extvac_stats_end(Relation rel, LVExtStatCounters *counters,
-				  ExtVacReport *report)
+				 PgStat_VacuumRelationCounts *report)
 {
 	WalUsage	walusage;
 	BufferUsage	bufusage;
@@ -603,9 +603,9 @@ extvac_stats_start_idx(Relation rel, IndexBulkDeleteResult *stats,
 
 void
 extvac_stats_end_idx(Relation rel, IndexBulkDeleteResult *stats,
-					 LVExtStatCountersIdx *counters, ExtVacReport *report)
+					 LVExtStatCountersIdx *counters, PgStat_VacuumRelationCounts *report)
 {
-	memset(report, 0, sizeof(ExtVacReport));
+	memset(report, 0, sizeof(PgStat_VacuumRelationCounts));
 
 	extvac_stats_end(rel, &counters->common, report);
 	report->type = PGSTAT_EXTVAC_INDEX;
@@ -1127,33 +1127,18 @@ heap_vacuum_rel(Relation rel, VacuumParams *params,
 	 *
 	 * We are ready to send vacuum statistics information for heap relations.
 	 */
-	if(pgstat_track_vacuum_statistics)
-	{
-		/* Make generic extended vacuum stats report and
-		 * fill heap-specific extended stats fields.
-		 */
-		extvac_stats_end(vacrel->rel, &extVacCounters, &(vacrel->extVacReport));
-		accumulate_heap_vacuum_statistics(&extVacCounters, vacrel);
 
-		pgstat_report_vacuum(RelationGetRelid(rel),
+	pgstat_report_vacuum(RelationGetRelid(rel),
 						 rel->rd_rel->relisshared,
 						 Max(vacrel->new_live_tuples, 0),
 						 vacrel->recently_dead_tuples +
- 						 vacrel->missed_dead_tuples,
-						 starttime,
-						 &(vacrel->extVacReport));
+						 vacrel->missed_dead_tuples,
+						 starttime);
 
-	}
-	else
-	{
-		pgstat_report_vacuum(RelationGetRelid(rel),
-							 rel->rd_rel->relisshared,
-							 Max(vacrel->new_live_tuples, 0),
-							 vacrel->recently_dead_tuples +
-							 vacrel->missed_dead_tuples,
-							 starttime,
-							 NULL);
-	}
+	/* Make generic extended vacuum stats report and fill heap-specific extended stats fields */
+	extvac_stats_end(vacrel->rel, &extVacCounters, &(vacrel->extVacReport));
+	accumulate_heap_vacuum_statistics(&extVacCounters, vacrel);
+	pgstat_report_tab_vacuum_extstats(vacrel->reloid, rel->rd_rel->relisshared, &(vacrel->extVacReport));
 
 	pgstat_progress_end_command();
 
@@ -3364,7 +3349,7 @@ lazy_vacuum_one_index(Relation indrel, IndexBulkDeleteResult *istat,
 	IndexVacuumInfo ivinfo;
 	LVSavedErrInfo saved_err_info;
 	LVExtStatCountersIdx extVacCounters;
-	ExtVacReport extVacReport;
+	PgStat_VacuumRelationCounts extVacReport;
 
 	/* Set initial statistics values to gather vacuum statistics for the index */
 	extvac_stats_start_idx(indrel, istat, &extVacCounters);
@@ -3395,14 +3380,10 @@ lazy_vacuum_one_index(Relation indrel, IndexBulkDeleteResult *istat,
 	istat = vac_bulkdel_one_index(&ivinfo, istat, vacrel->dead_items,
 								  vacrel->dead_items_info);
 
-	if(pgstat_track_vacuum_statistics)
-	{
-		/* Make extended vacuum stats report for index */
-		extvac_stats_end_idx(indrel, istat, &extVacCounters, &extVacReport);
-		pgstat_report_vacuum(RelationGetRelid(indrel),
-								indrel->rd_rel->relisshared,
-								0, 0, 0, &extVacReport);
-	}
+	/* Make extended vacuum stats report for index */
+	extvac_stats_end_idx(indrel, istat, &extVacCounters, &extVacReport);
+	pgstat_report_tab_vacuum_extstats(vacrel->indoid, indrel->rd_rel->relisshared,
+										&extVacReport);
 
 	/* Revert to the previous phase information for error traceback */
 	restore_vacuum_error_info(vacrel, &saved_err_info);
@@ -3429,7 +3410,7 @@ lazy_cleanup_one_index(Relation indrel, IndexBulkDeleteResult *istat,
 	IndexVacuumInfo ivinfo;
 	LVSavedErrInfo saved_err_info;
 	LVExtStatCountersIdx extVacCounters;
-	ExtVacReport extVacReport;
+	PgStat_VacuumRelationCounts extVacReport;
 
 	/* Set initial statistics values to gather vacuum statistics for the index */
 	extvac_stats_start_idx(indrel, istat, &extVacCounters);
@@ -3459,14 +3440,10 @@ lazy_cleanup_one_index(Relation indrel, IndexBulkDeleteResult *istat,
 
 	istat = vac_cleanup_one_index(&ivinfo, istat);
 
-	if(pgstat_track_vacuum_statistics)
-	{
-		/* Make extended vacuum stats report for index */
-		extvac_stats_end_idx(indrel, istat, &extVacCounters, &extVacReport);
-		pgstat_report_vacuum(RelationGetRelid(indrel),
-								indrel->rd_rel->relisshared,
-								0, 0, 0, &extVacReport);
-	}
+	/* Make extended vacuum stats report for index */
+	extvac_stats_end_idx(indrel, istat, &extVacCounters, &extVacReport);
+	pgstat_report_tab_vacuum_extstats(vacrel->indoid, indrel->rd_rel->relisshared,
+										&extVacReport);
 
 	/* Revert to the previous phase information for error traceback */
 	restore_vacuum_error_info(vacrel, &saved_err_info);
@@ -4081,7 +4058,7 @@ vacuum_error_callback(void *arg)
 	{
 		case VACUUM_ERRCB_PHASE_SCAN_HEAP:
 			if(geterrelevel() == ERROR)
-					pgstat_report_vacuum_error(errinfo->reloid, PGSTAT_EXTVAC_TABLE);
+					pgstat_report_vacuum_error();
 
 			if (BlockNumberIsValid(errinfo->blkno))
 			{
@@ -4099,7 +4076,7 @@ vacuum_error_callback(void *arg)
 
 		case VACUUM_ERRCB_PHASE_VACUUM_HEAP:
 			if(geterrelevel() == ERROR)
-				pgstat_report_vacuum_error(errinfo->reloid, PGSTAT_EXTVAC_TABLE);
+				pgstat_report_vacuum_error();
 
 			if (BlockNumberIsValid(errinfo->blkno))
 			{
@@ -4117,7 +4094,7 @@ vacuum_error_callback(void *arg)
 
 		case VACUUM_ERRCB_PHASE_VACUUM_INDEX:
 			if(geterrelevel() == ERROR)
-				pgstat_report_vacuum_error(errinfo->indoid, PGSTAT_EXTVAC_INDEX);
+				pgstat_report_vacuum_error();
 
 			errcontext("while vacuuming index \"%s\" of relation \"%s.%s\"",
 					   errinfo->indname, errinfo->relnamespace, errinfo->relname);
@@ -4125,7 +4102,7 @@ vacuum_error_callback(void *arg)
 
 		case VACUUM_ERRCB_PHASE_INDEX_CLEANUP:
 			if(geterrelevel() == ERROR)
-				pgstat_report_vacuum_error(errinfo->indoid, PGSTAT_EXTVAC_INDEX);
+				pgstat_report_vacuum_error();
 
 			errcontext("while cleaning up index \"%s\" of relation \"%s.%s\"",
 					   errinfo->indname, errinfo->relnamespace, errinfo->relname);
@@ -4133,7 +4110,7 @@ vacuum_error_callback(void *arg)
 
 		case VACUUM_ERRCB_PHASE_TRUNCATE:
 			if(geterrelevel() == ERROR)
-				pgstat_report_vacuum_error(errinfo->reloid, PGSTAT_EXTVAC_TABLE);
+				pgstat_report_vacuum_error();
 
 			if (BlockNumberIsValid(errinfo->blkno))
 				errcontext("while truncating relation \"%s.%s\" to %u blocks",
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index fbaed5359ad..72c8e339c45 100644
--- a/src/backend/catalog/heap.c
+++ b/src/backend/catalog/heap.c
@@ -1873,6 +1873,7 @@ heap_drop_with_catalog(Oid relid)
 
 	/* ensure that stats are dropped if transaction commits */
 	pgstat_drop_relation(rel);
+	pgstat_vacuum_relation_delete_pending_cb(RelationGetRelid(rel));
 
 	/*
 	 * Close relcache entry, but *keep* AccessExclusiveLock on the relation
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 739a92bdcc1..e4fa754aab4 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -2327,6 +2327,7 @@ index_drop(Oid indexId, bool concurrent, bool concurrent_lock_mode)
 
 	/* ensure that stats are dropped if transaction commits */
 	pgstat_drop_relation(userIndexRelation);
+	pgstat_vacuum_relation_delete_pending_cb(RelationGetRelid(userIndexRelation));
 
 	/*
 	 * Close and flush the index's relcache entry, to ensure relcache doesn't
diff --git a/src/backend/commands/dbcommands.c b/src/backend/commands/dbcommands.c
index 5fbbcdaabb1..c4b910cd928 100644
--- a/src/backend/commands/dbcommands.c
+++ b/src/backend/commands/dbcommands.c
@@ -1789,6 +1789,7 @@ dropdb(const char *dbname, bool missing_ok, bool force)
 	 * Tell the cumulative stats system to forget it immediately, too.
 	 */
 	pgstat_drop_database(db_id);
+	pgstat_drop_vacuum_database(db_id);
 
 	/*
 	 * Except for the deletion of the catalog row, subsequent actions are not
diff --git a/src/backend/commands/vacuumparallel.c b/src/backend/commands/vacuumparallel.c
index 000388a565f..9401e46d755 100644
--- a/src/backend/commands/vacuumparallel.c
+++ b/src/backend/commands/vacuumparallel.c
@@ -869,7 +869,7 @@ parallel_vacuum_process_one_index(ParallelVacuumState *pvs, Relation indrel,
 	IndexBulkDeleteResult *istat_res;
 	IndexVacuumInfo ivinfo;
 	LVExtStatCountersIdx extVacCounters;
-	ExtVacReport extVacReport;
+	PgStat_VacuumRelationCounts extVacReport;
 
 	/*
 	 * Update the pointer to the corresponding bulk-deletion result if someone
@@ -909,14 +909,10 @@ parallel_vacuum_process_one_index(ParallelVacuumState *pvs, Relation indrel,
 				 RelationGetRelationName(indrel));
 	}
 
-	if(pgstat_track_vacuum_statistics)
-	{
-		/* Make extended vacuum stats report for index */
-		extvac_stats_end_idx(indrel, istat_res, &extVacCounters, &extVacReport);
-		pgstat_report_vacuum(RelationGetRelid(indrel),
-								indrel->rd_rel->relisshared,
-								0, 0, 0, &extVacReport);
-	}
+	/* Make extended vacuum stats report for index */
+	extvac_stats_end_idx(indrel, istat_res, &extVacCounters, &extVacReport);
+	pgstat_report_tab_vacuum_extstats(RelationGetRelid(indrel), indrel->rd_rel->relisshared,
+										&extVacReport);
 
 	/*
 	 * Copy the index bulk-deletion result returned from ambulkdelete and
diff --git a/src/backend/utils/activity/Makefile b/src/backend/utils/activity/Makefile
index 9c2443e1ecd..183f7514d2d 100644
--- a/src/backend/utils/activity/Makefile
+++ b/src/backend/utils/activity/Makefile
@@ -27,6 +27,7 @@ OBJS = \
 	pgstat_function.o \
 	pgstat_io.o \
 	pgstat_relation.o \
+	pgstat_vacuum.o \
 	pgstat_replslot.o \
 	pgstat_shmem.o \
 	pgstat_slru.o \
diff --git a/src/backend/utils/activity/pgstat.c b/src/backend/utils/activity/pgstat.c
index 85557736a3a..ca764a3a214 100644
--- a/src/backend/utils/activity/pgstat.c
+++ b/src/backend/utils/activity/pgstat.c
@@ -478,6 +478,34 @@ static const PgStat_KindInfo pgstat_kind_builtin_infos[PGSTAT_KIND_BUILTIN_SIZE]
 		.reset_all_cb = pgstat_wal_reset_all_cb,
 		.snapshot_cb = pgstat_wal_snapshot_cb,
 	},
+	[PGSTAT_KIND_VACUUM_DB] = {
+		.name = "vacuum statistics",
+
+		.fixed_amount = false,
+		.write_to_file = true,
+		/* so pg_stat_database entries can be seen in all databases */
+		.accessed_across_databases = true,
+
+		.shared_size = sizeof(PgStatShared_VacuumDB),
+		.shared_data_off = offsetof(PgStatShared_VacuumDB, stats),
+		.shared_data_len = sizeof(((PgStatShared_VacuumDB *) 0)->stats),
+		.pending_size = sizeof(PgStat_VacuumDBCounts),
+
+		.flush_pending_cb = pgstat_vacuum_db_flush_cb,
+	},
+	[PGSTAT_KIND_VACUUM_RELATION] = {
+		.name = "vacuum statistics",
+
+		.fixed_amount = false,
+		.write_to_file = true,
+
+		.shared_size = sizeof(PgStatShared_VacuumRelation),
+		.shared_data_off = offsetof(PgStatShared_VacuumRelation, stats),
+		.shared_data_len = sizeof(((PgStatShared_VacuumRelation *) 0)->stats),
+		.pending_size = sizeof(PgStat_RelationVacuumPending),
+
+		.flush_pending_cb = pgstat_vacuum_relation_flush_cb
+	},
 };
 
 /*
diff --git a/src/backend/utils/activity/pgstat_database.c b/src/backend/utils/activity/pgstat_database.c
index 65207d30378..80e6c7c229a 100644
--- a/src/backend/utils/activity/pgstat_database.c
+++ b/src/backend/utils/activity/pgstat_database.c
@@ -46,6 +46,15 @@ pgstat_drop_database(Oid databaseid)
 	pgstat_drop_transactional(PGSTAT_KIND_DATABASE, databaseid, InvalidOid);
 }
 
+/*
+ * Remove entry for the database being dropped.
+ */
+void
+pgstat_drop_vacuum_database(Oid databaseid)
+{
+	pgstat_drop_transactional(PGSTAT_KIND_VACUUM_DB, databaseid, InvalidOid);
+}
+
 /*
  * Called from autovacuum.c to report startup of an autovacuum process.
  * We are called before InitPostgres is done, so can't rely on MyDatabaseId;
@@ -485,7 +494,6 @@ pgstat_database_flush_cb(PgStat_EntryRef *entry_ref, bool nowait)
 	pgstat_unlock_entry(entry_ref);
 
 	memset(pendingent, 0, sizeof(*pendingent));
-	memset(&(pendingent)->vacuum_ext, 0, sizeof(ExtVacReport));
 
 	return true;
 }
diff --git a/src/backend/utils/activity/pgstat_relation.c b/src/backend/utils/activity/pgstat_relation.c
index 1695680ea62..acc8f0b8a52 100644
--- a/src/backend/utils/activity/pgstat_relation.c
+++ b/src/backend/utils/activity/pgstat_relation.c
@@ -47,8 +47,6 @@ static void add_tabstat_xact_level(PgStat_TableStatus *pgstat_info, int nest_lev
 static void ensure_tabstat_xact_level(PgStat_TableStatus *pgstat_info);
 static void save_truncdrop_counters(PgStat_TableXactStatus *trans, bool is_drop);
 static void restore_truncdrop_counters(PgStat_TableXactStatus *trans);
-static void pgstat_accumulate_extvac_stats(ExtVacReport *dst, ExtVacReport *src,
-							   bool accumulate_reltype_specific_info);
 
 
 /*
@@ -205,50 +203,17 @@ pgstat_drop_relation(Relation rel)
 	}
 }
 
-/* ---------
- * pgstat_report_vacuum_error() -
- *
- *	Tell the collector about an (auto)vacuum interruption.
- * ---------
- */
-void
-pgstat_report_vacuum_error(Oid tableoid, ExtVacReportType m_type)
-{
-	PgStat_EntryRef *entry_ref;
-	PgStatShared_Relation *shtabentry;
-	PgStat_StatTabEntry *tabentry;
-	Oid			dboid =  MyDatabaseId;
-	PgStat_StatDBEntry *dbentry;	/* pending database entry */
-
-	if (!pgstat_track_counts)
-		return;
-
-	entry_ref = pgstat_get_entry_ref_locked(PGSTAT_KIND_RELATION,
-											dboid, tableoid, false);
-
-	shtabentry = (PgStatShared_Relation *) entry_ref->shared_stats;
-	tabentry = &shtabentry->stats;
-
-	tabentry->vacuum_ext.type = m_type;
-	pgstat_unlock_entry(entry_ref);
-
-	dbentry = pgstat_prep_database_pending(dboid);
-	dbentry->vacuum_ext.errors++;
-	dbentry->vacuum_ext.type = m_type;
-}
-
 /*
  * Report that the table was just vacuumed and flush IO statistics.
  */
 void
 pgstat_report_vacuum(Oid tableoid, bool shared,
 					 PgStat_Counter livetuples, PgStat_Counter deadtuples,
-					 TimestampTz starttime, ExtVacReport *params)
+					 TimestampTz starttime)
 {
 	PgStat_EntryRef *entry_ref;
 	PgStatShared_Relation *shtabentry;
 	PgStat_StatTabEntry *tabentry;
-	PgStatShared_Database *dbentry;
 	Oid			dboid = (shared ? InvalidOid : MyDatabaseId);
 	TimestampTz ts;
 	PgStat_Counter elapsedtime;
@@ -270,8 +235,6 @@ pgstat_report_vacuum(Oid tableoid, bool shared,
 	tabentry->live_tuples = livetuples;
 	tabentry->dead_tuples = deadtuples;
 
-	pgstat_accumulate_extvac_stats(&tabentry->vacuum_ext, params, true);
-
 	/*
 	 * It is quite possible that a non-aggressive VACUUM ended up skipping
 	 * various pages, however, we'll zero the insert counter here regardless.
@@ -307,16 +270,6 @@ pgstat_report_vacuum(Oid tableoid, bool shared,
 	 */
 	pgstat_flush_io(false);
 	(void) pgstat_flush_backend(false, PGSTAT_BACKEND_FLUSH_IO);
-
-	if (dboid != InvalidOid)
-	{
-		entry_ref = pgstat_get_entry_ref_locked(PGSTAT_KIND_DATABASE,
-											dboid, InvalidOid, false);
-		dbentry = (PgStatShared_Database *) entry_ref->shared_stats;
-
-		pgstat_accumulate_extvac_stats(&dbentry->stats.vacuum_ext, params, false);
-		pgstat_unlock_entry(entry_ref);
-	}
 }
 
 /*
@@ -951,6 +904,12 @@ pgstat_relation_flush_cb(PgStat_EntryRef *entry_ref, bool nowait)
 	return true;
 }
 
+void
+pgstat_vacuum_relation_delete_pending_cb(Oid relid)
+{
+	pgstat_drop_transactional(PGSTAT_KIND_VACUUM_RELATION, relid, InvalidOid);
+}
+
 void
 pgstat_relation_delete_pending_cb(PgStat_EntryRef *entry_ref)
 {
@@ -1053,60 +1012,4 @@ restore_truncdrop_counters(PgStat_TableXactStatus *trans)
 		trans->tuples_updated = trans->updated_pre_truncdrop;
 		trans->tuples_deleted = trans->deleted_pre_truncdrop;
 	}
-}
-
-static void
-pgstat_accumulate_extvac_stats(ExtVacReport *dst, ExtVacReport *src,
-							   bool accumulate_reltype_specific_info)
-{
-	if(!pgstat_track_vacuum_statistics)
-		return;
-
-	dst->total_blks_read += src->total_blks_read;
-	dst->total_blks_hit += src->total_blks_hit;
-	dst->total_blks_dirtied += src->total_blks_dirtied;
-	dst->total_blks_written += src->total_blks_written;
-	dst->wal_bytes += src->wal_bytes;
-	dst->wal_fpi += src->wal_fpi;
-	dst->wal_records += src->wal_records;
-	dst->blk_read_time += src->blk_read_time;
-	dst->blk_write_time += src->blk_write_time;
-	dst->delay_time += src->delay_time;
-	dst->total_time += src->total_time;
-	dst->wraparound_failsafe_count += src->wraparound_failsafe_count;
-	dst->errors += src->errors;
-
-	if (!accumulate_reltype_specific_info)
-		return;
-
-	if (dst->type == PGSTAT_EXTVAC_INVALID)
-		dst->type = src->type;
-
-	Assert(src->type == PGSTAT_EXTVAC_INVALID || src->type == dst->type);
-
-	if (dst->type == src->type)
-	{
-		dst->blks_fetched += src->blks_fetched;
-		dst->blks_hit += src->blks_hit;
-
-		if (dst->type == PGSTAT_EXTVAC_TABLE)
-		{
-			dst->table.pages_scanned += src->table.pages_scanned;
-			dst->table.pages_removed += src->table.pages_removed;
-			dst->table.vm_new_frozen_pages += src->table.vm_new_frozen_pages;
-			dst->table.vm_new_visible_pages += src->table.vm_new_visible_pages;
-			dst->table.vm_new_visible_frozen_pages += src->table.vm_new_visible_frozen_pages;
-			dst->tuples_deleted += src->tuples_deleted;
-			dst->table.tuples_frozen += src->table.tuples_frozen;
-			dst->table.recently_dead_tuples += src->table.recently_dead_tuples;
-			dst->table.index_vacuum_count += src->table.index_vacuum_count;
-			dst->table.missed_dead_pages += src->table.missed_dead_pages;
-			dst->table.missed_dead_tuples += src->table.missed_dead_tuples;
-		}
-		else if (dst->type == PGSTAT_EXTVAC_INDEX)
-		{
-			dst->index.pages_deleted += src->index.pages_deleted;
-			dst->tuples_deleted += src->tuples_deleted;
-		}
-	}
 }
\ No newline at end of file
diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index c2acdcf0e0e..423a256c83a 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -2275,89 +2275,29 @@ pg_stat_get_vacuum_tables(PG_FUNCTION_ARGS)
 	#define PG_STAT_GET_VACUUM_TABLES_STATS_COLS 26
 
 	Oid						relid = PG_GETARG_OID(0);
-	PgStat_StatTabEntry     *tabentry;
-	ExtVacReport 			*extvacuum;
+	PgStat_VacuumRelationCounts 			*extvacuum;
+	PgStat_VacuumRelationCounts *pending;
 	TupleDesc				 tupdesc;
 	Datum					 values[PG_STAT_GET_VACUUM_TABLES_STATS_COLS] = {0};
 	bool					 nulls[PG_STAT_GET_VACUUM_TABLES_STATS_COLS] = {0};
 	char					 buf[256];
 	int						 i = 0;
-	ExtVacReport allzero;
+	PgStat_VacuumRelationCounts allzero;
 
-	/* Initialise attributes information in the tuple descriptor */
-	tupdesc = CreateTemplateTupleDesc(PG_STAT_GET_VACUUM_TABLES_STATS_COLS);
-
-	TupleDescInitEntry(tupdesc, (AttrNumber) ++i, "relid",
-					   INT4OID, -1, 0);
-	TupleDescInitEntry(tupdesc, (AttrNumber) ++i, "total_blks_read",
-					   INT8OID, -1, 0);
-	TupleDescInitEntry(tupdesc, (AttrNumber) ++i, "total_blks_hit",
-					   INT8OID, -1, 0);
-	TupleDescInitEntry(tupdesc, (AttrNumber) ++i, "total_blks_dirtied",
-					   INT8OID, -1, 0);
-	TupleDescInitEntry(tupdesc, (AttrNumber) ++i, "total_blks_written",
-					   INT8OID, -1, 0);
-	TupleDescInitEntry(tupdesc, (AttrNumber) ++i, "rel_blks_read",
-					   INT8OID, -1, 0);
-	TupleDescInitEntry(tupdesc, (AttrNumber) ++i, "rel_blks_hit",
-					   INT8OID, -1, 0);
-	TupleDescInitEntry(tupdesc, (AttrNumber) ++i, "pages_scanned",
-					   INT8OID, -1, 0);
-	TupleDescInitEntry(tupdesc, (AttrNumber) ++i, "pages_removed",
-					   INT8OID, -1, 0);
-	TupleDescInitEntry(tupdesc, (AttrNumber) ++i, "vm_new_frozen_pages",
-					   INT8OID, -1, 0);
-	TupleDescInitEntry(tupdesc, (AttrNumber) ++i, "vm_new_visible_pages",
-					   INT8OID, -1, 0);
-	TupleDescInitEntry(tupdesc, (AttrNumber) ++i, "vm_new_visible_frozen_pages",
-					   INT8OID, -1, 0);
-	TupleDescInitEntry(tupdesc, (AttrNumber) ++i, "missed_dead_pages",
-					   INT8OID, -1, 0);
-	TupleDescInitEntry(tupdesc, (AttrNumber) ++i, "tuples_deleted",
-					   INT8OID, -1, 0);
-	TupleDescInitEntry(tupdesc, (AttrNumber) ++i, "tuples_frozen",
-					   INT8OID, -1, 0);
-	TupleDescInitEntry(tupdesc, (AttrNumber) ++i, "recently_dead_tuples",
-					   INT8OID, -1, 0);
-	TupleDescInitEntry(tupdesc, (AttrNumber) ++i, "missed_dead_tuples",
-					   INT8OID, -1, 0);
-	TupleDescInitEntry(tupdesc, (AttrNumber) ++i, "wraparound_failsafe_count",
-					   INT4OID, -1, 0);
-	TupleDescInitEntry(tupdesc, (AttrNumber) ++i, "index_vacuum_count",
-					   INT8OID, -1, 0);
-	TupleDescInitEntry(tupdesc, (AttrNumber) ++i, "wal_records",
-					   INT8OID, -1, 0);
-	TupleDescInitEntry(tupdesc, (AttrNumber) ++i, "wal_fpi",
-					   INT8OID, -1, 0);
-	TupleDescInitEntry(tupdesc, (AttrNumber) ++i, "wal_bytes",
-					   NUMERICOID, -1, 0);
+	/* Build a tuple descriptor for our result type */
+	if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
+		elog(ERROR, "return type must be a row type");
 
-	TupleDescInitEntry(tupdesc, (AttrNumber) ++i, "blk_read_time",
-					   FLOAT8OID, -1, 0);
-	TupleDescInitEntry(tupdesc, (AttrNumber) ++i, "blk_write_time",
-					   FLOAT8OID, -1, 0);
-
-	TupleDescInitEntry(tupdesc, (AttrNumber) ++i, "delay_time",
-					   FLOAT8OID, -1, 0);
-	TupleDescInitEntry(tupdesc, (AttrNumber) ++i, "total_time",
-					   FLOAT8OID, -1, 0);
-
-	Assert(i == PG_STAT_GET_VACUUM_TABLES_STATS_COLS);
-
-	BlessTupleDesc(tupdesc);
+	pending = pgstat_fetch_stat_vacuum_tabentry(relid, MyDatabaseId);
 
-	tabentry = pgstat_fetch_stat_tabentry(relid);
-
-	if (tabentry == NULL)
+	if (pending == NULL)
 	{
 		/* If the subscription is not found, initialise its stats */
-		memset(&allzero, 0, sizeof(ExtVacReport));
+		memset(&allzero, 0, sizeof(PgStat_VacuumRelationCounts));
 		extvacuum = &allzero;
 	}
 	else
-	{
-		extvacuum = &(tabentry->vacuum_ext);
-	}
+		extvacuum = pending;
 
 	i = 0;
 
@@ -2416,69 +2356,29 @@ pg_stat_get_vacuum_indexes(PG_FUNCTION_ARGS)
 	#define PG_STAT_GET_VACUUM_INDEX_STATS_COLS	16
 
 	Oid						relid = PG_GETARG_OID(0);
-	PgStat_StatTabEntry     *tabentry;
-	ExtVacReport 			*extvacuum;
+	PgStat_VacuumRelationCounts 			*extvacuum;
+	PgStat_VacuumRelationCounts *pending;
 	TupleDesc				 tupdesc;
 	Datum					 values[PG_STAT_GET_VACUUM_INDEX_STATS_COLS] = {0};
 	bool					 nulls[PG_STAT_GET_VACUUM_INDEX_STATS_COLS] = {0};
 	char					 buf[256];
 	int						 i = 0;
-	ExtVacReport allzero;
-
-	/* Initialise attributes information in the tuple descriptor */
-	tupdesc = CreateTemplateTupleDesc(PG_STAT_GET_VACUUM_INDEX_STATS_COLS);
-
-	TupleDescInitEntry(tupdesc, (AttrNumber) ++i, "relid",
-					   INT4OID, -1, 0);
-	TupleDescInitEntry(tupdesc, (AttrNumber) ++i, "total_ blks_read",
-					   INT8OID, -1, 0);
-	TupleDescInitEntry(tupdesc, (AttrNumber) ++i, "total_blks_hit",
-					   INT8OID, -1, 0);
-	TupleDescInitEntry(tupdesc, (AttrNumber) ++i, "total_blks_dirtied",
-					   INT8OID, -1, 0);
-	TupleDescInitEntry(tupdesc, (AttrNumber) ++i, "total_blks_written",
-					   INT8OID, -1, 0);
-	TupleDescInitEntry(tupdesc, (AttrNumber) ++i, "rel_blks_read",
-					   INT8OID, -1, 0);
-	TupleDescInitEntry(tupdesc, (AttrNumber) ++i, "rel_blks_hit",
-					   INT8OID, -1, 0);
-	TupleDescInitEntry(tupdesc, (AttrNumber) ++i, "pages_deleted",
-					   INT8OID, -1, 0);
-	TupleDescInitEntry(tupdesc, (AttrNumber) ++i, "tuples_deleted",
-					   INT8OID, -1, 0);
-	TupleDescInitEntry(tupdesc, (AttrNumber) ++i, "wal_records",
-					   INT8OID, -1, 0);
-	TupleDescInitEntry(tupdesc, (AttrNumber) ++i, "wal_fpi",
-					   INT8OID, -1, 0);
-	TupleDescInitEntry(tupdesc, (AttrNumber) ++i, "wal_bytes",
-					   NUMERICOID, -1, 0);
+	PgStat_VacuumRelationCounts allzero;
 
-	TupleDescInitEntry(tupdesc, (AttrNumber) ++i, "blk_read_time",
-					   FLOAT8OID, -1, 0);
-	TupleDescInitEntry(tupdesc, (AttrNumber) ++i, "blk_write_time",
-					   FLOAT8OID, -1, 0);
+	/* Build a tuple descriptor for our result type */
+	if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
+		elog(ERROR, "return type must be a row type");
 
-	TupleDescInitEntry(tupdesc, (AttrNumber) ++i, "delay_time",
-					   FLOAT8OID, -1, 0);
-	TupleDescInitEntry(tupdesc, (AttrNumber) ++i, "total_time",
-					   FLOAT8OID, -1, 0);
+	pending = pgstat_fetch_stat_vacuum_tabentry(relid, MyDatabaseId);
 
-	Assert(i == PG_STAT_GET_VACUUM_INDEX_STATS_COLS);
-
-	BlessTupleDesc(tupdesc);
-
-	tabentry = pgstat_fetch_stat_tabentry(relid);
-
-	if (tabentry == NULL)
+	if (pending == NULL)
 	{
 		/* If the subscription is not found, initialise its stats */
-		memset(&allzero, 0, sizeof(ExtVacReport));
+		memset(&allzero, 0, sizeof(PgStat_VacuumRelationCounts));
 		extvacuum = &allzero;
 	}
 	else
-	{
-		extvacuum = &(tabentry->vacuum_ext);
-	}
+		extvacuum = pending;
 
 	i = 0;
 
@@ -2523,67 +2423,29 @@ pg_stat_get_vacuum_database(PG_FUNCTION_ARGS)
 	#define PG_STAT_GET_VACUUM_DATABASE_STATS_COLS	14
 
 	Oid						 dbid = PG_GETARG_OID(0);
-	PgStat_StatDBEntry 		*dbentry;
-	ExtVacReport 			*extvacuum;
+	PgStat_VacuumDBCounts	*extvacuum;
+	PgStat_VacuumDBCounts	*pending;
 	TupleDesc				 tupdesc;
 	Datum					 values[PG_STAT_GET_VACUUM_DATABASE_STATS_COLS] = {0};
 	bool					 nulls[PG_STAT_GET_VACUUM_DATABASE_STATS_COLS] = {0};
 	char					 buf[256];
 	int						 i = 0;
-	ExtVacReport allzero;
-
-	/* Initialise attributes information in the tuple descriptor */
-	tupdesc = CreateTemplateTupleDesc(PG_STAT_GET_VACUUM_DATABASE_STATS_COLS);
-
-	TupleDescInitEntry(tupdesc, (AttrNumber) ++i, "dbid",
-					   INT4OID, -1, 0);
-	TupleDescInitEntry(tupdesc, (AttrNumber) ++i, "total_ blks_read",
-					   INT8OID, -1, 0);
-	TupleDescInitEntry(tupdesc, (AttrNumber) ++i, "total_blks_hit",
-					   INT8OID, -1, 0);
-	TupleDescInitEntry(tupdesc, (AttrNumber) ++i, "total_blks_dirtied",
-					   INT8OID, -1, 0);
-	TupleDescInitEntry(tupdesc, (AttrNumber) ++i, "total_blks_written",
-					   INT8OID, -1, 0);
-	TupleDescInitEntry(tupdesc, (AttrNumber) ++i, "wal_records",
-					   INT8OID, -1, 0);
-	TupleDescInitEntry(tupdesc, (AttrNumber) ++i, "wal_fpi",
-					   INT8OID, -1, 0);
-	TupleDescInitEntry(tupdesc, (AttrNumber) ++i, "wal_bytes",
-					   NUMERICOID, -1, 0);
+	PgStat_VacuumDBCounts allzero;
 
-	TupleDescInitEntry(tupdesc, (AttrNumber) ++i, "blk_read_time",
-					   FLOAT8OID, -1, 0);
-	TupleDescInitEntry(tupdesc, (AttrNumber) ++i, "blk_write_time",
-					   FLOAT8OID, -1, 0);
+	/* Build a tuple descriptor for our result type */
+	if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
+		elog(ERROR, "return type must be a row type");
 
-	TupleDescInitEntry(tupdesc, (AttrNumber) ++i, "delay_time",
-					   FLOAT8OID, -1, 0);
-	TupleDescInitEntry(tupdesc, (AttrNumber) ++i, "total_time",
-					   FLOAT8OID, -1, 0);
-	TupleDescInitEntry(tupdesc, (AttrNumber) ++i, "wraparound_failsafe_count",
-					   INT4OID, -1, 0);
-	TupleDescInitEntry(tupdesc, (AttrNumber) ++i, "errors",
-					   INT4OID, -1, 0);
+	pending = pgstat_fetch_stat_vacuum_dbentry(dbid);
 
-	Assert(i == PG_STAT_GET_VACUUM_DATABASE_STATS_COLS);
-
-	BlessTupleDesc(tupdesc);
-
-	dbentry = pgstat_fetch_stat_dbentry(dbid);
-
-	if (dbentry == NULL)
+	if (pending == NULL)
 	{
 		/* If the subscription is not found, initialise its stats */
-		memset(&allzero, 0, sizeof(ExtVacReport));
+		memset(&allzero, 0, sizeof(PgStat_VacuumRelationCounts));
 		extvacuum = &allzero;
 	}
 	else
-	{
-		extvacuum = &(dbentry->vacuum_ext);
-	}
-
-	i = 0;
+		extvacuum = pending;
 
 	values[i++] = ObjectIdGetDatum(dbid);
 
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index fb134f3402e..f895151ca09 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -432,5 +432,5 @@ extern double anl_get_next_S(double t, int n, double *stateptr);
 extern void extvac_stats_start_idx(Relation rel, IndexBulkDeleteResult *stats,
 					   LVExtStatCountersIdx *counters);
 extern void extvac_stats_end_idx(Relation rel, IndexBulkDeleteResult *stats,
-					 LVExtStatCountersIdx *counters, ExtVacReport *report);
+					 LVExtStatCountersIdx *counters, PgStat_VacuumRelationCounts *report);
 #endif							/* VACUUM_H */
diff --git a/src/include/pgstat.h b/src/include/pgstat.h
index f8158aa353c..f57a96d3aa2 100644
--- a/src/include/pgstat.h
+++ b/src/include/pgstat.h
@@ -116,12 +116,60 @@ typedef enum ExtVacReportType
 {
 	PGSTAT_EXTVAC_INVALID = 0,
 	PGSTAT_EXTVAC_TABLE = 1,
-	PGSTAT_EXTVAC_INDEX = 2
+	PGSTAT_EXTVAC_INDEX = 2,
+	PGSTAT_EXTVAC_DB = 3,
 } ExtVacReportType;
 
 /* ----------
+ * PgStat_TableCounts			The actual per-table counts kept by a backend
+ *
+ * This struct should contain only actual event counters, because we make use
+ * of pg_memory_is_all_zeros() to detect whether there are any stats updates
+ * to apply.
  *
- * ExtVacReport
+ * It is a component of PgStat_TableStatus (within-backend state).
+ *
+ * Note: for a table, tuples_returned is the number of tuples successfully
+ * fetched by heap_getnext, while tuples_fetched is the number of tuples
+ * successfully fetched by heap_fetch under the control of bitmap indexscans.
+ * For an index, tuples_returned is the number of index entries returned by
+ * the index AM, while tuples_fetched is the number of tuples successfully
+ * fetched by heap_fetch under the control of simple indexscans for this index.
+ *
+ * tuples_inserted/updated/deleted/hot_updated/newpage_updated count attempted
+ * actions, regardless of whether the transaction committed.  delta_live_tuples,
+ * delta_dead_tuples, and changed_tuples are set depending on commit or abort.
+ * Note that delta_live_tuples and delta_dead_tuples can be negative!
+ * ----------
+ */
+typedef struct PgStat_TableCounts
+{
+	PgStat_Counter numscans;
+
+	PgStat_Counter tuples_returned;
+	PgStat_Counter tuples_fetched;
+
+	PgStat_Counter tuples_inserted;
+	PgStat_Counter tuples_updated;
+	PgStat_Counter tuples_deleted;
+	PgStat_Counter tuples_hot_updated;
+	PgStat_Counter tuples_newpage_updated;
+	bool		truncdropped;
+
+	PgStat_Counter delta_live_tuples;
+	PgStat_Counter delta_dead_tuples;
+	PgStat_Counter changed_tuples;
+
+	PgStat_Counter blocks_fetched;
+	PgStat_Counter blocks_hit;
+
+	PgStat_Counter rev_all_visible_pages;
+	PgStat_Counter rev_all_frozen_pages;
+} PgStat_TableCounts;
+
+/* ----------
+ *
+ * PgStat_VacuumRelationCounts
  *
  * Additional statistics of vacuum processing over a relation.
  * pages_removed is the amount by which the physically shrank,
@@ -129,7 +177,7 @@ typedef enum ExtVacReportType
  * pages_deleted refer to free space within the index file
  * ----------
  */
-typedef struct ExtVacReport
+typedef struct PgStat_VacuumRelationCounts
 {
 	/* number of blocks missed, hit, dirtied and written during a vacuum of specific relation */
 	int64		total_blks_read;
@@ -154,7 +202,6 @@ typedef struct ExtVacReport
 
 	int64		tuples_deleted;		/* tuples deleted by vacuum */
 
-	int32		errors;
 	int32		wraparound_failsafe_count;	/* the number of times to prevent wraparound problem */
 
 	ExtVacReportType type;		/* heap, index, etc. */
@@ -192,61 +239,44 @@ typedef struct ExtVacReport
 			int64		pages_deleted;		/* number of pages deleted by vacuum */
 		}			index;
 	} /* per_type_stats */;
-} ExtVacReport;
+} PgStat_VacuumRelationCounts;
 
-/* ----------
- * PgStat_TableCounts			The actual per-table counts kept by a backend
- *
- * This struct should contain only actual event counters, because we make use
- * of pg_memory_is_all_zeros() to detect whether there are any stats updates
- * to apply.
- *
- * It is a component of PgStat_TableStatus (within-backend state).
- *
- * Note: for a table, tuples_returned is the number of tuples successfully
- * fetched by heap_getnext, while tuples_fetched is the number of tuples
- * successfully fetched by heap_fetch under the control of bitmap indexscans.
- * For an index, tuples_returned is the number of index entries returned by
- * the index AM, while tuples_fetched is the number of tuples successfully
- * fetched by heap_fetch under the control of simple indexscans for this index.
- *
- * tuples_inserted/updated/deleted/hot_updated/newpage_updated count attempted
- * actions, regardless of whether the transaction committed.  delta_live_tuples,
- * delta_dead_tuples, and changed_tuples are set depending on commit or abort.
- * Note that delta_live_tuples and delta_dead_tuples can be negative!
- * ----------
- */
-typedef struct PgStat_TableCounts
+typedef struct PgStat_VacuumRelationStatus
 {
-	PgStat_Counter numscans;
+	Oid			id;				/* table's OID */
+	bool		shared;			/* is it a shared catalog? */
+	PgStat_VacuumRelationCounts counts;	/* event counts to be sent */
+} PgStat_VacuumRelationStatus;
 
-	PgStat_Counter tuples_returned;
-	PgStat_Counter tuples_fetched;
+typedef struct PgStat_VacuumDBCounts
+{
+	Oid			dbjid;
+	/* number of blocks missed, hit, dirtied and written during a vacuum of specific relation */
+	int64		total_blks_read;
+	int64		total_blks_hit;
+	int64		total_blks_dirtied;
+	int64		total_blks_written;
 
-	PgStat_Counter tuples_inserted;
-	PgStat_Counter tuples_updated;
-	PgStat_Counter tuples_deleted;
-	PgStat_Counter tuples_hot_updated;
-	PgStat_Counter tuples_newpage_updated;
-	bool		truncdropped;
+	/* blocks missed and hit for just the heap during a vacuum of specific relation */
+	int64		blks_fetched;
+	int64		blks_hit;
 
-	PgStat_Counter delta_live_tuples;
-	PgStat_Counter delta_dead_tuples;
-	PgStat_Counter changed_tuples;
+	/* Vacuum WAL usage stats */
+	int64		wal_records;	/* wal usage: number of WAL records */
+	int64		wal_fpi;		/* wal usage: number of WAL full page images produced */
+	uint64		wal_bytes;		/* wal usage: size of WAL records produced */
 
-	PgStat_Counter blocks_fetched;
-	PgStat_Counter blocks_hit;
+	/* Time stats. */
+	double		blk_read_time;	/* time spent reading pages, in msec */
+	double		blk_write_time; /* time spent writing pages, in msec */
+	double		delay_time;		/* how long vacuum slept in vacuum delay point, in msec */
+	double		total_time;		/* total time of a vacuum operation, in msec */
 
-	PgStat_Counter rev_all_visible_pages;
-	PgStat_Counter rev_all_frozen_pages;
+	int64		tuples_deleted;		/* tuples deleted by vacuum */
 
-	/*
-	 * Additional cumulative stat on vacuum operations.
-	 * Use an expensive structure as an abstraction for different types of
-	 * relations.
-	 */
-	ExtVacReport	vacuum_ext;
-} PgStat_TableCounts;
+	int32		errors;
+	int32		wraparound_failsafe_count;	/* the number of times to prevent wraparound problem */
+} PgStat_VacuumDBCounts;
 
 /* ----------
  * PgStat_TableStatus			Per-table status within a backend
@@ -272,6 +302,12 @@ typedef struct PgStat_TableStatus
 	Relation	relation;		/* rel that is using this entry */
 } PgStat_TableStatus;
 
+typedef struct PgStat_RelationVacuumPending
+{
+	Oid			id;				/* table's OID */
+	PgStat_VacuumRelationCounts counts;	/* event counts to be sent */
+} PgStat_RelationVacuumPending;
+
 /* ----------
  * PgStat_TableXactStatus		Per-table, per-subtransaction status
  * ----------
@@ -468,8 +504,6 @@ typedef struct PgStat_StatDBEntry
 	PgStat_Counter parallel_workers_launched;
 
 	TimestampTz stat_reset_timestamp;
-
-	ExtVacReport vacuum_ext;		/* extended vacuum statistics */
 } PgStat_StatDBEntry;
 
 typedef struct PgStat_StatFuncEntry
@@ -551,8 +585,6 @@ typedef struct PgStat_StatTabEntry
 
 	PgStat_Counter rev_all_visible_pages;
 	PgStat_Counter rev_all_frozen_pages;
-
-	ExtVacReport vacuum_ext;
 } PgStat_StatTabEntry;
 
 /* ------
@@ -760,11 +792,11 @@ extern void pgstat_unlink_relation(Relation rel);
 
 extern void pgstat_report_vacuum(Oid tableoid, bool shared,
 								 PgStat_Counter livetuples, PgStat_Counter deadtuples,
-								 TimestampTz starttime, ExtVacReport *params);
+								 TimestampTz starttime);
 extern void pgstat_report_analyze(Relation rel,
 								  PgStat_Counter livetuples, PgStat_Counter deadtuples,
 								  bool resetcounter, TimestampTz starttime);
-extern void pgstat_report_vacuum_error(Oid tableoid, ExtVacReportType m_type);
+extern void pgstat_report_vacuum_error();
 
 /*
  * If stats are enabled, but pending data hasn't been prepared yet, call
@@ -895,6 +927,15 @@ extern int	pgstat_get_transactional_drops(bool isCommit, struct xl_xact_stats_it
 extern void pgstat_execute_transactional_drops(int ndrops, struct xl_xact_stats_item *items, bool is_redo);
 
 
+extern void pgstat_drop_vacuum_database(Oid databaseid);
+extern void pgstat_vacuum_relation_delete_pending_cb(Oid relid);
+extern void
+pgstat_report_tab_vacuum_extstats(Oid tableoid, bool shared,
+								  PgStat_VacuumRelationCounts *params);
+extern PgStat_RelationVacuumPending * find_vacuum_relation_entry(Oid relid);
+extern PgStat_VacuumDBCounts *pgstat_prep_vacuum_database_pending(Oid dboid);
+extern PgStat_VacuumRelationCounts *pgstat_fetch_stat_vacuum_tabentry(Oid relid, Oid dbid);
+PgStat_VacuumDBCounts *pgstat_fetch_stat_vacuum_dbentry(Oid dbid);
 /*
  * Functions in pgstat_wal.c
  */
diff --git a/src/include/utils/pgstat_internal.h b/src/include/utils/pgstat_internal.h
index d5557e6e998..140adbcdbd6 100644
--- a/src/include/utils/pgstat_internal.h
+++ b/src/include/utils/pgstat_internal.h
@@ -439,6 +439,18 @@ typedef struct PgStatShared_Relation
 	PgStat_StatTabEntry stats;
 } PgStatShared_Relation;
 
+typedef struct PgStatShared_VacuumDB
+{
+	PgStatShared_Common header;
+	PgStat_VacuumDBCounts stats;
+} PgStatShared_VacuumDB;
+
+typedef struct PgStatShared_VacuumRelation
+{
+	PgStatShared_Common header;
+	PgStat_VacuumRelationCounts stats;
+} PgStatShared_VacuumRelation;
+
 typedef struct PgStatShared_Function
 {
 	PgStatShared_Common header;
@@ -607,6 +619,9 @@ extern PgStat_EntryRef *pgstat_fetch_pending_entry(PgStat_Kind kind,
 extern void *pgstat_fetch_entry(PgStat_Kind kind, Oid dboid, uint64 objid);
 extern void pgstat_snapshot_fixed(PgStat_Kind kind);
 
+bool pgstat_vacuum_db_flush_cb(PgStat_EntryRef *entry_ref, bool nowait);
+extern bool pgstat_vacuum_relation_flush_cb(PgStat_EntryRef *entry_ref, bool nowait);
+
 
 /*
  * Functions in pgstat_archiver.c
diff --git a/src/include/utils/pgstat_kind.h b/src/include/utils/pgstat_kind.h
index f44169fd5a3..454661f9d6a 100644
--- a/src/include/utils/pgstat_kind.h
+++ b/src/include/utils/pgstat_kind.h
@@ -38,9 +38,11 @@
 #define PGSTAT_KIND_IO	10
 #define PGSTAT_KIND_SLRU	11
 #define PGSTAT_KIND_WAL	12
+#define PGSTAT_KIND_VACUUM_DB	13
+#define PGSTAT_KIND_VACUUM_RELATION	14
 
 #define PGSTAT_KIND_BUILTIN_MIN PGSTAT_KIND_DATABASE
-#define PGSTAT_KIND_BUILTIN_MAX PGSTAT_KIND_WAL
+#define PGSTAT_KIND_BUILTIN_MAX PGSTAT_KIND_VACUUM_RELATION
 #define PGSTAT_KIND_BUILTIN_SIZE (PGSTAT_KIND_BUILTIN_MAX + 1)
 
 /* Custom stats kinds */
