diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 441a912..529116f 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -397,6 +397,18 @@ static bool doRequestWalReceiverReply;
  */
 static XLogRecPtr RedoStartLSN = InvalidXLogRecPtr;
 
+/*
+ * It stores the start timestamp of the operations that occur during process
+ * startup.
+ */
+static TimestampTz operationStartTimestamp;
+
+/*
+ * It stores the timestamp of the last log that happened during the logging
+ * of the process startup progress.
+ */
+static TimestampTz operationLastLogTimestamp;
+
 /*----------
  * Shared-memory data structures for XLOG control
  *
@@ -7323,6 +7335,8 @@ StartupXLOG(void)
 					(errmsg("redo starts at %X/%X",
 							LSN_FORMAT_ARGS(ReadRecPtr))));
 
+			SetCurrentOperationStartTimestamp();
+
 			/*
 			 * main redo apply loop
 			 */
@@ -7330,6 +7344,8 @@ StartupXLOG(void)
 			{
 				bool		switchedTLI = false;
 
+				log_startup_process_progress("Performing crash recovery", (void *) EndRecPtr, false);
+
 #ifdef WAL_DEBUG
 				if (XLOG_DEBUG ||
 					(rmid == RM_XACT_ID && trace_recovery_messages <= DEBUG2) ||
@@ -12929,3 +12945,107 @@ XLogRequestWalReceiverReply(void)
 {
 	doRequestWalReceiverReply = true;
 }
+
+/*
+ * GetCurrentOperationStartTimestamp
+ * 		Fetches the start timestamp of the current operation.
+ */
+TimestampTz
+GetCurrentOperationStartTimestamp(void)
+{
+	return operationStartTimestamp;
+}
+
+/*
+ * GetCurrentOperationLastLogTimestamp
+ * 		Fetches the timestamp of the last log written for the current
+ * 		operation.
+ */
+TimestampTz
+GetCurrentOperationLastLogTimestamp(void)
+{
+	return operationLastLogTimestamp;
+}
+
+/*
+ * SetCurrentOperationStartTimestamp
+ * 		Sets the start timestamp of the current operation.
+ */
+void
+SetCurrentOperationStartTimestamp(void)
+{
+	operationStartTimestamp = GetCurrentTimestamp();
+	operationLastLogTimestamp = GetCurrentTimestamp();
+}
+
+/*
+ * SetCurrentOperationLastLogTimestamp
+ *		Sets the current log timestamp so that this value can be used to
+ *		compare for the minimum duration of the logging process.
+ */
+void
+SetCurrentOperationLastLogTimestamp(void)
+{
+	operationLastLogTimestamp = GetCurrentTimestamp();
+}
+
+/*
+ * log_startup_process_progress
+ * 		Logs the progress of the opeartions occur during startup of the
+ * 		process.
+ */
+void
+log_startup_process_progress(char *operation, void *data, bool is_complete)
+{
+	long        secs;
+	int         usecs;
+	int         msecs;
+	bool        exceeded_duration;
+
+	if (log_min_duration_startup_process < 0)
+		return;
+
+	if (is_complete)
+	{
+		TimestampDifference(GetCurrentOperationStartTimestamp(),
+							GetCurrentTimestamp(),
+							&secs, &usecs);
+		msecs = usecs / 1000;
+
+		ereport(LOG,(errmsg("%s completed after %ld.%03d ms",
+							operation, secs * 1000 + msecs,
+							usecs % 1000),
+					 errhidestmt(true)));
+
+		return;
+	}
+
+	TimestampDifference(GetCurrentOperationLastLogTimestamp(),
+						GetCurrentTimestamp(),
+						&secs, &usecs);
+	msecs = usecs / 1000;
+	msecs = secs * 1000 + msecs;
+
+	exceeded_duration = (log_min_duration_startup_process > 0 &&
+						 (msecs >= log_min_duration_startup_process));
+
+	if (exceeded_duration)
+	{
+		SetCurrentOperationLastLogTimestamp();
+		TimestampDifference(GetCurrentOperationStartTimestamp(),
+							GetCurrentTimestamp(),
+							&secs, &usecs);
+		msecs = usecs / 1000;
+
+		if (strcmp(operation, "Performing crash recovery") == 0)
+			ereport(LOG,(errmsg("%s, elapsed time: %ld.%03d ms,  current LSN: %X/%X",
+								operation, secs * 1000 + msecs,
+								usecs % 1000, LSN_FORMAT_ARGS((XLogRecPtr) data)),
+						 errhidestmt(true)));
+		else
+			ereport(LOG,(errmsg("%s, elapsed time: %ld.%03d ms,  current path: %s",
+								operation, secs * 1000 + msecs,
+								usecs % 1000, (char *) data),
+						 errhidestmt(true)));
+	}
+}
diff --git a/src/backend/storage/file/fd.c b/src/backend/storage/file/fd.c
index e8cd7ef..2a8d535 100644
--- a/src/backend/storage/file/fd.c
+++ b/src/backend/storage/file/fd.c
@@ -3337,6 +3337,7 @@ SyncDataDirectory(void)
 	if (!enableFsync)
 		return;
 
+	SetCurrentOperationStartTimestamp();
 	/*
 	 * If pg_wal is a symlink, we'll need to recurse into it separately,
 	 * because the first walkdir below will ignore it.
@@ -3386,6 +3387,7 @@ SyncDataDirectory(void)
 				continue;
 
 			snprintf(path, MAXPGPATH, "pg_tblspc/%s", de->d_name);
+			log_startup_process_progress("Syncing data directory", path, false);
 			do_syncfs(path);
 		}
 		FreeDir(dir);
@@ -3421,6 +3423,7 @@ SyncDataDirectory(void)
 	if (xlog_is_symlink)
 		walkdir("pg_wal", datadir_fsync_fname, false, LOG);
 	walkdir("pg_tblspc", datadir_fsync_fname, true, LOG);
+	log_startup_process_progress("Syncing data directory", NULL, true);
 }
 
 /*
@@ -3460,6 +3463,7 @@ walkdir(const char *path,
 			continue;
 
 		snprintf(subpath, sizeof(subpath), "%s/%s", path, de->d_name);
+		log_startup_process_progress("Syncing data directory", subpath, false);
 
 		switch (get_dirent_type(subpath, de, process_symlinks, elevel))
 		{
diff --git a/src/backend/storage/file/reinit.c b/src/backend/storage/file/reinit.c
index 40c758d..ce1f46f 100644
--- a/src/backend/storage/file/reinit.c
+++ b/src/backend/storage/file/reinit.c
@@ -51,6 +51,8 @@ ResetUnloggedRelations(int op)
 	MemoryContext tmpctx,
 				oldctx;
 
+	SetCurrentOperationStartTimestamp();
+
 	/* Log it. */
 	elog(DEBUG1, "resetting unlogged relations: cleanup %d init %d",
 		 (op & UNLOGGED_RELATION_CLEANUP) != 0,
@@ -88,6 +90,7 @@ ResetUnloggedRelations(int op)
 
 	FreeDir(spc_dir);
 
+	log_startup_process_progress("Resetting unlogged relations", NULL, true);
 	/*
 	 * Restore memory context.
 	 */
@@ -136,6 +139,8 @@ ResetUnloggedRelationsInTablespaceDir(const char *tsdirname, int op)
 
 		snprintf(dbspace_path, sizeof(dbspace_path), "%s/%s",
 				 tsdirname, de->d_name);
+		log_startup_process_progress("Resetting unlogged relations",
+									 dbspace_path, false);
 		ResetUnloggedRelationsInDbspaceDir(dbspace_path, op);
 	}
 
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 87bc688..7fa6684 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -663,6 +663,8 @@ static char *recovery_target_lsn_string;
 /* should be static, but commands/variable.c needs to get at this */
 char	   *role_string;
 
+/* Used to log the progress of process startup */
+int         log_min_duration_startup_process = -1;
 
 /*
  * Displayable names for context types (enum GucContext)
@@ -3539,6 +3541,18 @@ static struct config_int ConfigureNamesInt[] =
 		check_client_connection_check_interval, NULL, NULL
 	},
 
+	{
+		{"log_min_duration_startup_process", PGC_SUSET, LOGGING_WHEN,
+			gettext_noop("Sets the minimum time duration after every time duration "
+						 "the progress of the process startup will be logged."),
+			gettext_noop("Zero prints all messages. -1 turns this feature off."),
+			GUC_UNIT_MS
+		},
+		&log_min_duration_startup_process,
+		-1, -1, INT_MAX,
+		NULL, NULL, NULL
+	},
+
 	/* End-of-list marker */
 	{
 		{NULL, 0, 0, NULL, NULL}, NULL, 0, 0, 0, NULL, NULL, NULL
diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample
index ddbb6dc..545e7ba 100644
--- a/src/backend/utils/misc/postgresql.conf.sample
+++ b/src/backend/utils/misc/postgresql.conf.sample
@@ -521,6 +521,10 @@
 					# are logged regardless of their duration; 1.0 logs all
 					# statements from all transactions, 0.0 never logs
 
+#log_min_duration_startup_process = -1	# -1 is disabled, 0 logs all available
+					# messages during server startup, > 0 indicates the time
+					# duration after every time duration it logs the progress.
+
 # - What to Log -
 
 #debug_print_parse = off
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index 77187c1..a84082a 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -391,6 +391,13 @@ extern void do_pg_abort_backup(int code, Datum arg);
 extern void register_persistent_abort_backup_handler(void);
 extern SessionBackupState get_backup_status(void);
 
+extern TimestampTz GetCurrentOperationStartTimestamp(void);
+extern TimestampTz GetCurrentOperationLastLogTimestamp(void);
+extern void SetCurrentOperationStartTimestamp(void);
+extern void SetCurrentOperationLastLogTimestamp(void);
+extern void log_startup_process_progress(char *operation, void *data,
+										 bool is_complete);
+
 /* File path names (all relative to $PGDATA) */
 #define RECOVERY_SIGNAL_FILE	"recovery.signal"
 #define STANDBY_SIGNAL_FILE		"standby.signal"
diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h
index a7c3a49..2e9658d 100644
--- a/src/include/utils/guc.h
+++ b/src/include/utils/guc.h
@@ -282,6 +282,8 @@ extern int	tcp_user_timeout;
 extern bool trace_sort;
 #endif
 
+extern int  log_min_duration_startup_process;
+
 /*
  * Functions exported by guc.c
  */
