diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql
index ccc030f..beedf90 100644
--- a/src/backend/catalog/system_views.sql
+++ b/src/backend/catalog/system_views.sql
@@ -631,6 +631,18 @@ CREATE VIEW pg_stat_activity AS
     WHERE S.datid = D.oid AND
             S.usesysid = U.oid;
 
+CREATE VIEW pg_stat_vacuum_progress AS
+    SELECT
+			S.pid,
+            S.total_pages,
+            S.scanned_pages,
+			S.total_heap_pages,
+			S.scanned_heap_pages,
+            S.total_index_pages,
+            S.scanned_index_pages,
+			S.percent_complete
+    FROM pg_stat_get_vacuum_progress(NULL) AS S;
+
 CREATE VIEW pg_stat_replication AS
     SELECT
             S.pid,
diff --git a/src/backend/commands/vacuumlazy.c b/src/backend/commands/vacuumlazy.c
index a01cfb4..d4a31ef 100644
--- a/src/backend/commands/vacuumlazy.c
+++ b/src/backend/commands/vacuumlazy.c
@@ -439,7 +439,13 @@ lazy_scan_heap(Relation onerel, LVRelStats *vacrelstats,
 			   Relation *Irel, int nindexes, bool scan_all)
 {
 	BlockNumber nblocks,
-				blkno;
+				blkno,
+				total_pages,
+				scanned_total_pages = 0,
+				total_heap_pages,
+				rel_index_pages = 0,
+				total_index_pages = 0,
+				scanned_index_pages = 0;
 	HeapTupleData tuple;
 	char	   *relname;
 	BlockNumber empty_pages,
@@ -471,7 +477,14 @@ lazy_scan_heap(Relation onerel, LVRelStats *vacrelstats,
 	indstats = (IndexBulkDeleteResult **)
 		palloc0(nindexes * sizeof(IndexBulkDeleteResult *));
 
-	nblocks = RelationGetNumberOfBlocks(onerel);
+	total_heap_pages = nblocks = RelationGetNumberOfBlocks(onerel);
+
+	for (i = 0; i < nindexes; i++)
+		rel_index_pages += RelationGetNumberOfBlocks(Irel[i]);
+
+	total_index_pages = rel_index_pages;
+	total_pages = total_heap_pages + rel_index_pages;
+
 	vacrelstats->rel_pages = nblocks;
 	vacrelstats->scanned_pages = 0;
 	vacrelstats->nonempty_pages = 0;
@@ -520,7 +533,11 @@ lazy_scan_heap(Relation onerel, LVRelStats *vacrelstats,
 		vacuum_delay_point();
 	}
 	if (next_not_all_visible_block >= SKIP_PAGES_THRESHOLD)
+	{
 		skipping_all_visible_blocks = true;
+		total_heap_pages = total_heap_pages - next_not_all_visible_block;
+		total_pages = total_pages - next_not_all_visible_block;
+	}
 	else
 		skipping_all_visible_blocks = false;
 
@@ -559,7 +576,11 @@ lazy_scan_heap(Relation onerel, LVRelStats *vacrelstats,
 			 * following blocks.
 			 */
 			if (next_not_all_visible_block - blkno > SKIP_PAGES_THRESHOLD)
+			{
 				skipping_all_visible_blocks = true;
+				total_heap_pages = total_heap_pages - (next_not_all_visible_block - blkno);
+				total_pages = total_pages - (next_not_all_visible_block - blkno);
+			}
 			else
 				skipping_all_visible_blocks = false;
 			all_visible_according_to_vm = false;
@@ -596,11 +617,30 @@ lazy_scan_heap(Relation onerel, LVRelStats *vacrelstats,
 			/* Log cleanup info before we touch indexes */
 			vacuum_log_cleanup_info(onerel, vacrelstats);
 
+			/*
+			 * If passes through indexes exceed 1 add
+			 * pages equal to rel_index_pages to the count of
+			 * total pages to be scanned.
+			 */
+			if (vacrelstats->num_index_scans >= 1)
+			{
+				total_index_pages = total_index_pages + rel_index_pages;
+				total_pages = total_heap_pages + total_index_pages;
+			}
+
 			/* Remove index entries */
 			for (i = 0; i < nindexes; i++)
+			{
 				lazy_vacuum_index(Irel[i],
 								  &indstats[i],
 								  vacrelstats);
+				scanned_index_pages += RelationGetNumberOfBlocks(Irel[i]);
+				scanned_total_pages = scanned_total_pages + RelationGetNumberOfBlocks(Irel[i]);
+				/* Report progress to the statistics collector */
+				pgstat_report_progress(total_pages, scanned_total_pages, total_heap_pages,
+										vacrelstats->scanned_pages, total_index_pages,
+										scanned_index_pages);
+			}
 			/* Remove tuples from heap */
 			lazy_vacuum_heap(onerel, vacrelstats);
 
@@ -658,6 +698,7 @@ lazy_scan_heap(Relation onerel, LVRelStats *vacrelstats,
 				UnlockReleaseBuffer(buf);
 				vacrelstats->scanned_pages++;
 				vacrelstats->pinskipped_pages++;
+				scanned_total_pages++;
 				continue;
 			}
 			LockBuffer(buf, BUFFER_LOCK_UNLOCK);
@@ -666,6 +707,7 @@ lazy_scan_heap(Relation onerel, LVRelStats *vacrelstats,
 		}
 
 		vacrelstats->scanned_pages++;
+		scanned_total_pages++;
 
 		page = BufferGetPage(buf);
 
@@ -1062,6 +1104,13 @@ lazy_scan_heap(Relation onerel, LVRelStats *vacrelstats,
 		 */
 		if (vacrelstats->num_dead_tuples == prev_dead_count)
 			RecordPageWithFreeSpace(onerel, blkno, freespace);
+
+		/*
+		 * Reporting vacuum progress to statistics collector
+		 */
+		pgstat_report_progress(total_pages, scanned_total_pages, total_heap_pages,
+								vacrelstats->scanned_pages, total_index_pages,
+								scanned_index_pages);
 	}
 
 	pfree(frozen);
@@ -1093,11 +1142,30 @@ lazy_scan_heap(Relation onerel, LVRelStats *vacrelstats,
 		/* Log cleanup info before we touch indexes */
 		vacuum_log_cleanup_info(onerel, vacrelstats);
 
+		/*
+		 * If passes through indexes exceed 1 add
+		 * pages equal to rel_index_pages to the count of
+		 * total pages to be scanned.
+		 */
+		if (vacrelstats->num_index_scans >= 1)
+		{
+			total_index_pages = total_index_pages + rel_index_pages;
+			total_pages = total_heap_pages + total_index_pages;
+		}
+
 		/* Remove index entries */
 		for (i = 0; i < nindexes; i++)
+		{
 			lazy_vacuum_index(Irel[i],
 							  &indstats[i],
 							  vacrelstats);
+			scanned_index_pages += RelationGetNumberOfBlocks(Irel[i]);
+			scanned_total_pages = scanned_total_pages + RelationGetNumberOfBlocks(Irel[i]);
+			/* Report progress to the statistics collector */
+			pgstat_report_progress(total_pages, scanned_total_pages, total_heap_pages,
+									vacrelstats->scanned_pages, total_index_pages,
+									scanned_index_pages);
+		}
 		/* Remove tuples from heap */
 		lazy_vacuum_heap(onerel, vacrelstats);
 		vacrelstats->num_index_scans++;
diff --git a/src/backend/postmaster/pgstat.c b/src/backend/postmaster/pgstat.c
index ab018c4..793fee5 100644
--- a/src/backend/postmaster/pgstat.c
+++ b/src/backend/postmaster/pgstat.c
@@ -2731,7 +2731,6 @@ pgstat_bestart(void)
 	beentry->st_clienthostname[NAMEDATALEN - 1] = '\0';
 	beentry->st_appname[NAMEDATALEN - 1] = '\0';
 	beentry->st_activity[pgstat_track_activity_query_size - 1] = '\0';
-
 	pgstat_increment_changecount_after(beentry);
 
 	/* Update app name to current GUC setting */
@@ -2851,6 +2850,37 @@ pgstat_report_activity(BackendState state, const char *cmd_str)
 	pgstat_increment_changecount_after(beentry);
 }
 
+/* ---------------------------------------------
+ * Called from VACUUM  after every heap page scan or index scan
+ * to report progress
+ * ---------------------------------------------
+ */
+
+void
+pgstat_report_progress(BlockNumber total_pages, BlockNumber scanned_pages,
+						BlockNumber heap_total_pages, BlockNumber heap_scanned_pages,
+						BlockNumber index_total_pages, BlockNumber index_scanned_pages)
+{
+	volatile PgBackendStatus *beentry = MyBEEntry;
+
+	if (!beentry)
+		return;
+
+	if (!pgstat_track_activities)
+		return;
+
+	pgstat_increment_changecount_before(beentry);
+	beentry->progress_param_float[0] = scanned_pages * 100 / total_pages;
+	beentry->progress_param[0] = total_pages;
+	beentry->progress_param[1] = scanned_pages;
+	beentry->progress_param[2] = heap_total_pages;
+	beentry->progress_param[3] = heap_scanned_pages;
+	beentry->progress_param[4] = index_total_pages;
+	beentry->progress_param[5] = index_scanned_pages;
+	pgstat_increment_changecount_after(beentry);
+
+}
+
 /* ----------
  * pgstat_report_appname() -
  *
@@ -3005,6 +3035,7 @@ pgstat_read_current_status(void)
 				strcpy(localactivity, (char *) beentry->st_activity);
 				localentry->backendStatus.st_activity = localactivity;
 				localentry->backendStatus.st_ssl = beentry->st_ssl;
+
 #ifdef USE_SSL
 				if (beentry->st_ssl)
 				{
diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index f7c9bf6..197aa52 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -53,6 +53,7 @@ extern Datum pg_stat_get_function_self_time(PG_FUNCTION_ARGS);
 
 extern Datum pg_stat_get_backend_idset(PG_FUNCTION_ARGS);
 extern Datum pg_stat_get_activity(PG_FUNCTION_ARGS);
+extern Datum pg_stat_get_vacuum_progress(PG_FUNCTION_ARGS);
 extern Datum pg_backend_pid(PG_FUNCTION_ARGS);
 extern Datum pg_stat_get_backend_pid(PG_FUNCTION_ARGS);
 extern Datum pg_stat_get_backend_dbid(PG_FUNCTION_ARGS);
@@ -523,7 +524,110 @@ pg_stat_get_backend_idset(PG_FUNCTION_ARGS)
 		SRF_RETURN_DONE(funcctx);
 	}
 }
+/*
+ * Returns VACUUM progress values stored by each backend
+ * executing VACUUM.
+ */
+Datum
+pg_stat_get_vacuum_progress(PG_FUNCTION_ARGS)
+{
+#define PG_STAT_GET_PROGRESS_COLS	30
+	int			num_backends = pgstat_fetch_stat_numbackends();
+	int			curr_backend;
+	TupleDesc	tupdesc;
+	Tuplestorestate *tupstore;
+	ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+	MemoryContext per_query_ctx;
+	MemoryContext oldcontext;
+
+	/* check to see if caller supports us returning a tuplestore */
+	if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo))
+		ereport(ERROR,
+				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+				 errmsg("set-valued function called in context that cannot accept a set")));
+	if (!(rsinfo->allowedModes & SFRM_Materialize))
+		ereport(ERROR,
+				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+				 errmsg("materialize mode required, but it is not " \
+						"allowed in this context")));
+
+	/* 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");
+
+	per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
+	oldcontext = MemoryContextSwitchTo(per_query_ctx);
+
+	tupstore = tuplestore_begin_heap(true, false, work_mem);
+	rsinfo->returnMode = SFRM_Materialize;
+	rsinfo->setResult = tupstore;
+	rsinfo->setDesc = tupdesc;
+	MemoryContextSwitchTo(oldcontext);
+
+	for (curr_backend = 1; curr_backend <= num_backends; curr_backend++)
+	{
+		Datum		values[PG_STAT_GET_PROGRESS_COLS];
+		bool		nulls[PG_STAT_GET_PROGRESS_COLS];
+		LocalPgBackendStatus *local_beentry;
+		PgBackendStatus *beentry;
+
+		MemSet(values, 0, sizeof(values));
+		MemSet(nulls, 0, sizeof(nulls));
+
+		local_beentry = pgstat_fetch_stat_local_beentry(curr_backend);
+		if (!local_beentry)
+			continue;
+
+		beentry = &local_beentry->backendStatus;
+		/* Report values for only those backends which are running VACUUM */
+		if(!beentry || (strncmp(beentry->st_activity,"VACUUM",6)
+						&& strncmp(beentry->st_activity,"vacuum",6)))
+			continue;
+
+		values[0] = Int32GetDatum(beentry->st_procpid);
+		if (beentry->progress_param[0] != 0)
+			values[1] = UInt32GetDatum(beentry->progress_param[0]);
+		else
+			nulls[1] = true;
+
+		if (beentry->progress_param[1] != 0)
+			values[2] = UInt32GetDatum(beentry->progress_param[1]);
+		else
+			nulls[2] = true;
 
+		if (beentry->progress_param[2] != 0)
+			values[3] = UInt32GetDatum(beentry->progress_param[2]);
+		else
+			nulls[3] = true;
+
+		if (beentry->progress_param[3] != 0)
+			values[4] = UInt32GetDatum(beentry->progress_param[3]);
+		else
+			nulls[4] = true;
+
+		if (beentry->progress_param[4] != 0)
+			values[5] = UInt32GetDatum(beentry->progress_param[4]);
+		else
+			nulls[5] = true;
+
+		if (beentry->progress_param[5] != 0)
+			values[6] = UInt32GetDatum(beentry->progress_param[5]);
+		else
+			nulls[6] = true;
+
+		if (beentry->progress_param_float[0] != 0)
+			values[7] = Float8GetDatum(beentry->progress_param_float[0]);
+		else
+			nulls[7] = true;
+
+		tuplestore_putvalues(tupstore, tupdesc, values, nulls);
+	}
+
+	/* clean up and return the tuplestore */
+	tuplestore_donestoring(tupstore);
+
+	return (Datum) 0;
+}
 /*
  * Returns activity of PG backends.
  */
@@ -584,7 +688,6 @@ pg_stat_get_activity(PG_FUNCTION_ARGS)
 
 			if (!be || be->st_procpid != pid)
 				continue;
-
 		}
 
 		/* Get the next one in the list */
@@ -790,7 +893,6 @@ pg_stat_get_activity(PG_FUNCTION_ARGS)
 	return (Datum) 0;
 }
 
-
 Datum
 pg_backend_pid(PG_FUNCTION_ARGS)
 {
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 8ebf424..5ccce10 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -2308,7 +2308,6 @@ static struct config_int ConfigureNamesInt[] =
 		-1, -1, INT_MAX,
 		NULL, NULL, NULL
 	},
-
 	{
 		{"log_autovacuum_min_duration", PGC_SIGHUP, LOGGING_WHAT,
 			gettext_noop("Sets the minimum execution time above which "
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index ddf7c67..b0845d3 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -2779,6 +2779,9 @@ DATA(insert OID = 1936 (  pg_stat_get_backend_idset		PGNSP PGUID 12 1 100 0 0 f
 DESCR("statistics: currently active backend IDs");
 DATA(insert OID = 2022 (  pg_stat_get_activity			PGNSP PGUID 12 1 100 0 0 f f f f f t s 1 0 2249 "23" "{23,26,23,26,25,25,25,16,1184,1184,1184,1184,869,25,23,28,28,16,25,25,23,16,25}" "{i,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o}" "{pid,datid,pid,usesysid,application_name,state,query,waiting,xact_start,query_start,backend_start,state_change,client_addr,client_hostname,client_port,backend_xid,backend_xmin,ssl,sslversion,sslcipher,sslbits,sslcompression,sslclientdn}" _null_ _null_ pg_stat_get_activity _null_ _null_ _null_ ));
 DESCR("statistics: information about currently active backends");
+
+DATA(insert OID = 3308 (  pg_stat_get_vacuum_progress			PGNSP PGUID 12 1 1 0 0 f f f f f t s 1 0 2249 "23" "{23,23,23,23,23,23,23,23,701}" "{i,o,o,o,o,o,o,o,o}" "{pid,pid,total_pages,scanned_pages,total_heap_pages,scanned_heap_pages,total_index_pages,scanned_index_pages,percent_complete}" _null_ _null_ pg_stat_get_vacuum_progress _null_ _null_ _null_ ));
+
 DATA(insert OID = 3099 (  pg_stat_get_wal_senders	PGNSP PGUID 12 1 10 0 0 f f f f f t s 0 0 2249 "" "{23,25,3220,3220,3220,3220,23,25}" "{o,o,o,o,o,o,o,o}" "{pid,state,sent_location,write_location,flush_location,replay_location,sync_priority,sync_state}" _null_ _null_ pg_stat_get_wal_senders _null_ _null_ _null_ ));
 DESCR("statistics: information about currently active replication");
 DATA(insert OID = 2026 (  pg_backend_pid				PGNSP PGUID 12 1 0 0 0 f f f f t f s 0 0 23 "" _null_ _null_ _null_ _null_ _null_ pg_backend_pid _null_ _null_ _null_ ));
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index e3a31af..e5f1ac9 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -155,7 +155,6 @@ extern int	vacuum_freeze_table_age;
 extern int	vacuum_multixact_freeze_min_age;
 extern int	vacuum_multixact_freeze_table_age;
 
-
 /* in commands/vacuum.c */
 extern void ExecVacuum(VacuumStmt *vacstmt, bool isTopLevel);
 extern void vacuum(int options, RangeVar *relation, Oid relid,
diff --git a/src/include/pgstat.h b/src/include/pgstat.h
index 9ecc163..c4a665a 100644
--- a/src/include/pgstat.h
+++ b/src/include/pgstat.h
@@ -20,6 +20,7 @@
 #include "utils/hsearch.h"
 #include "utils/relcache.h"
 
+#include "storage/block.h"
 
 /* ----------
  * Paths for the statistics files (relative to installation's $PGDATA).
@@ -205,6 +206,8 @@ typedef struct PgStat_MsgHdr
 #define PGSTAT_MAX_MSG_SIZE 1000
 #define PGSTAT_MSG_PAYLOAD	(PGSTAT_MAX_MSG_SIZE - sizeof(PgStat_MsgHdr))
 
+#define N_PROGRESS_PARAM 10
+#define PROGRESS_MESSAGE_LENGTH 20
 
 /* ----------
  * PgStat_MsgDummy				A dummy message, ignored by the collector
@@ -776,6 +779,11 @@ typedef struct PgBackendStatus
 
 	/* current command string; MUST be null-terminated */
 	char	   *st_activity;
+
+	uint32 progress_param[N_PROGRESS_PARAM];
+	double	progress_param_float[N_PROGRESS_PARAM];
+	char progress_message[PROGRESS_MESSAGE_LENGTH][N_PROGRESS_PARAM];
+
 } PgBackendStatus;
 
 /*
@@ -928,6 +936,9 @@ extern void pgstat_initialize(void);
 extern void pgstat_bestart(void);
 
 extern void pgstat_report_activity(BackendState state, const char *cmd_str);
+extern void pgstat_report_progress(BlockNumber total_pages, BlockNumber scanned_pages,
+									BlockNumber total_heap_pages, BlockNumber scanned_heap_pages,
+									BlockNumber total_index_pages, BlockNumber scanned_index_pages);
 extern void pgstat_report_tempfile(size_t filesize);
 extern void pgstat_report_appname(const char *appname);
 extern void pgstat_report_xact_timestamp(TimestampTz tstamp);
