diff --git a/doc/xml/release.xml b/doc/xml/release.xml
index 87a125820..29c5a852d 100644
--- a/doc/xml/release.xml
+++ b/doc/xml/release.xml
@@ -48,6 +48,15 @@
                         <p>Partial multi-repository implementation.</p>
                     </release-item>
 
+                    <release-item>
+                        <release-item-contributor-list>
+                            <release-item-contributor id="cynthia.shang"/>
+                            <release-item-reviewer id="david.steele"/>
+                        </release-item-contributor-list>
+
+                        <p>Add backup verification to internal verify command.</p>
+                    </release-item>
+
                     <release-item>
                         <release-item-contributor-list>
                             <release-item-reviewer id="cynthia.shang"/>
diff --git a/src/command/verify/verify.c b/src/command/verify/verify.c
index 1f92e6cbb..2f7df9751 100644
--- a/src/command/verify/verify.c
+++ b/src/command/verify/verify.c
@@ -5,8 +5,9 @@ Verify the contents of the repository.
 ***********************************************************************************************************************************/
 #include "build.auto.h"
 
-#include <unistd.h>
 #include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
 
 #include "command/archive/common.h"
 #include "command/check/common.h"
@@ -36,11 +37,17 @@ Data Types and Structures
 #define FUNCTION_LOG_VERIFY_ARCHIVE_RESULT_FORMAT(value, buffer, bufferSize)                                                       \
     objToLog(&value, "VerifyArchiveResult", buffer, bufferSize)
 
+#define FUNCTION_LOG_VERIFY_BACKUP_RESULT_TYPE                                                                                     \
+    VerifyBackupResult
+#define FUNCTION_LOG_VERIFY_BACKUP_RESULT_FORMAT(value, buffer, bufferSize)                                                        \
+    objToLog(&value, "VerifyBackupResult", buffer, bufferSize)
+
 // Structure for verifying repository info files
 typedef struct VerifyInfoFile
 {
     InfoBackup *backup;                                             // Backup.info file contents
     InfoArchive *archive;                                           // Archive.info file contents
+    Manifest *manifest;                                             // Manifest file contents
     const String *checksum;                                         // File checksum
     int errorCode;                                                  // Error code else 0 for no error
 } VerifyInfoFile;
@@ -70,6 +77,31 @@ typedef struct VerifyInvalidFile
     VerifyResult reason;                                            // Reason file is invalid (e.g. incorrect checksum)
 } VerifyInvalidFile;
 
+// Status result of a backup
+typedef enum
+{
+    backupValid,                                                    // Default: All files in backup label repo passed verification
+    backupInvalid,                                                  // One of more files in backup label repo failed verification
+    backupMissingManifest,                                          // Backup manifest missing (backup may have expired)
+    backupInProgress,                                               // Backup appeared to be in progress (so was skipped)
+} VerifyBackupResultStatus;
+
+typedef struct VerifyBackupResult
+{
+    String *backupLabel;                                            // Label assigned to the backup
+    VerifyBackupResultStatus status;                                // Final status of the backup
+    bool fileVerifyComplete;                                        // Have all the files of the backup completed verification?
+    unsigned int totalFileManifest;                                 // Total number of backup files in the manifest
+    unsigned int totalFileVerify;                                   // Total number of backup files being verified
+    unsigned int totalFileValid;                                    // Total number of backup files that were verified and valid
+    String *backupPrior;                                            // Prior backup that this backup depends on, if any
+    unsigned int pgId;                                              // PG id will be used to find WAL for the backup in the repo
+    unsigned int pgVersion;                                         // PG version will be used with PG id to find WAL in the repo
+    String *archiveStart;                                           // First WAL segment in the backup
+    String *archiveStop;                                            // Last WAL segment in the backup
+    List *invalidFileList;                                          // List of invalid files found in the backup
+} VerifyBackupResult;
+
 // Job data stucture for processing and results collection
 typedef struct VerifyJobData
 {
@@ -78,14 +110,49 @@ typedef struct VerifyJobData
     StringList *walPathList;                                        // WAL path list for a single archive id
     StringList *walFileList;                                        // WAL file list for a single WAL path
     StringList *backupList;                                         // List of backups to verify
+    Manifest *manifest;                                             // Manifest contents with list of files to verify
+    unsigned int manifestFileIdx;                                   // Index of the file within the manifest file list to process
     String *currentBackup;                                          // In progress backup, if any
     const InfoPg *pgHistory;                                        // Database history list
-    bool backupProcessing;                                          // Are we processing WAL or are we processing backup
+    bool backupProcessing;                                          // Are we processing WAL or are we processing backups
+    const String *manifestCipherPass;                               // Cipher pass for reading backup manifests
     const String *walCipherPass;                                    // Cipher pass for reading WAL files
+    const String *backupCipherPass;                                 // Cipher pass for reading backup files referenced in a manifest
     unsigned int jobErrorTotal;                                     // Total errors that occurred during the job execution
     List *archiveIdResultList;                                      // Archive results
+    List *backupResultList;                                         // Backup results
 } VerifyJobData;
 
+/***********************************************************************************************************************************
+Helper function to add a file to an invalid file list
+***********************************************************************************************************************************/
+static void
+verifyInvalidFileAdd(List *invalidFileList, VerifyResult reason, const String *fileName)
+{
+    FUNCTION_TEST_BEGIN();
+        FUNCTION_TEST_PARAM(LIST, invalidFileList);                 // Invalid file list to add the filename to
+        FUNCTION_TEST_PARAM(ENUM, reason);                          // Reason for invalid file
+        FUNCTION_TEST_PARAM(STRING, fileName);                      // Name of invalid file
+    FUNCTION_TEST_END();
+
+    ASSERT(invalidFileList != NULL);
+    ASSERT(fileName != NULL);
+
+    MEM_CONTEXT_BEGIN(lstMemContext(invalidFileList))
+    {
+        VerifyInvalidFile invalidFile =
+        {
+            .fileName = strDup(fileName),
+            .reason = reason,
+        };
+
+        lstAdd(invalidFileList, &invalidFile);
+    }
+    MEM_CONTEXT_END();
+
+    FUNCTION_TEST_RETURN_VOID();
+}
+
 /***********************************************************************************************************************************
 Load a file into memory
 ***********************************************************************************************************************************/
@@ -142,8 +209,10 @@ verifyInfoFile(const String *pathFileName, bool keepFile, const String *cipherPa
             {
                 if (strBeginsWith(pathFileName, INFO_BACKUP_PATH_FILE_STR))
                     result.backup = infoBackupMove(infoBackupNewLoad(infoRead), memContextPrior());
-                else
+                else if (strBeginsWith(pathFileName, INFO_ARCHIVE_PATH_FILE_STR))
                     result.archive = infoArchiveMove(infoArchiveNewLoad(infoRead), memContextPrior());
+                else
+                    result.manifest = manifestMove(manifestNewLoad(infoRead), memContextPrior());
             }
             else
                 ioReadDrain(infoRead);
@@ -277,6 +346,136 @@ verifyBackupInfoFile(void)
     FUNCTION_LOG_RETURN(INFO_BACKUP, result);
 }
 
+/***********************************************************************************************************************************
+Get the manifest file
+***********************************************************************************************************************************/
+static Manifest *
+verifyManifestFile(
+    VerifyBackupResult *backupResult, const String *cipherPass, bool currentBackup, const InfoPg *pgHistory,
+    unsigned int *jobErrorTotal)
+{
+    FUNCTION_LOG_BEGIN(logLevelDebug);
+        FUNCTION_TEST_PARAM_P(VERIFY_BACKUP_RESULT, backupResult);  // The result set for the backup being processed
+        FUNCTION_TEST_PARAM(STRING, cipherPass);                    // Passphrase to access the manifest file
+        FUNCTION_LOG_PARAM(BOOL, currentBackup);                    // Is this possibly a backup currently in progress?
+        FUNCTION_TEST_PARAM(INFO_PG, pgHistory);                    // Database history
+        FUNCTION_TEST_PARAM_P(UINT, jobErrorTotal);                 // Pointer to the overall job error total
+    FUNCTION_LOG_END();
+
+    Manifest *result = NULL;
+
+    MEM_CONTEXT_TEMP_BEGIN()
+    {
+        String *fileName = strNewFmt(STORAGE_REPO_BACKUP "/%s/" BACKUP_MANIFEST_FILE, strZ(backupResult->backupLabel));
+
+        // Get the main manifest file
+        VerifyInfoFile verifyManifestInfo = verifyInfoFile(fileName, true, cipherPass);
+
+        // If the main file did not error, then report on the copy's status and check checksums
+        if (verifyManifestInfo.errorCode == 0)
+        {
+            result = verifyManifestInfo.manifest;
+
+            // The current in-progress backup is only notional until the main file is checked because the backup may have
+            // completed by the time the main manifest is checked here. So having a main manifest file means this backup is not
+            // (or is no longer) the currentBackup.
+            currentBackup = false;
+
+            // Attempt to load the copy and report on it's status but don't keep it in memory
+            VerifyInfoFile verifyManifestInfoCopy = verifyInfoFile(
+                strNewFmt("%s%s", strZ(fileName), INFO_COPY_EXT), false, cipherPass);
+
+            // If the copy loaded successfuly, then check the checksums
+            if (verifyManifestInfoCopy.errorCode == 0)
+            {
+                // If the manifest and manifest.copy checksums don't match each other than one (or both) of the files could be
+                // corrupt so log a warning but trust main
+                if (!strEq(verifyManifestInfo.checksum, verifyManifestInfoCopy.checksum))
+                    LOG_WARN_FMT("backup '%s' manifest.copy does not match manifest", strZ(backupResult->backupLabel));
+            }
+        }
+        else
+        {
+            // If this might be an in-progress backup and the main manifest is simply missing, it is assumed the backup is an
+            // actual in-progress backup and verification is skipped, otherwise, if the main is not simply missing, or this is not
+            // an in-progress backup then attempt to load the copy.
+            if (!(currentBackup && verifyManifestInfo.errorCode == errorTypeCode(&FileMissingError)))
+            {
+                currentBackup = false;
+
+                VerifyInfoFile verifyManifestInfoCopy = verifyInfoFile(
+                    strNewFmt("%s%s", strZ(fileName), INFO_COPY_EXT), true, cipherPass);
+
+                // If loaded successfully, then return the copy as usable
+                if (verifyManifestInfoCopy.errorCode == 0)
+                {
+                    LOG_WARN_FMT("%s/backup.manifest is missing or unusable, using copy", strZ(backupResult->backupLabel));
+
+                    result = verifyManifestInfoCopy.manifest;
+                }
+                else if (verifyManifestInfo.errorCode == errorTypeCode(&FileMissingError) &&
+                    verifyManifestInfoCopy.errorCode == errorTypeCode(&FileMissingError))
+                {
+                    backupResult->status = backupMissingManifest;
+
+                    LOG_WARN_FMT("manifest missing for '%s' - backup may have expired", strZ(backupResult->backupLabel));
+                }
+            }
+            else
+            {
+                backupResult->status = backupInProgress;
+
+                LOG_INFO_FMT("backup '%s' appears to be in progress, skipping", strZ(backupResult->backupLabel));
+            }
+        }
+
+        // If found a usable manifest then check that the database it was based on is in the history
+        if (result != NULL)
+        {
+            bool found = false;
+            const ManifestData *manData = manifestData(result);
+
+            // Confirm the PG database information from the manifest is in the history list
+            for (unsigned int infoPgIdx = 0; infoPgIdx < infoPgDataTotal(pgHistory); infoPgIdx++)
+            {
+                InfoPgData pgHistoryData = infoPgData(pgHistory, infoPgIdx);
+
+                if (pgHistoryData.id == manData->pgId && pgHistoryData.systemId == manData->pgSystemId &&
+                    pgHistoryData.version == manData->pgVersion)
+                {
+                    found = true;
+                    break;
+                }
+            }
+
+            // If the PG data is not found in the backup.info history, then error and reset the result
+            if (!found)
+            {
+                LOG_ERROR_FMT(
+                    errorTypeCode(&FileInvalidError),
+                    "'%s' may not be recoverable - PG data (id %u, version %s, system-id %" PRIu64 ") is not in the backup.info"
+                        " history, skipping",
+                    strZ(backupResult->backupLabel), manData->pgId, strZ(pgVersionToStr(manData->pgVersion)), manData->pgSystemId);
+
+                manifestFree(result);
+                result = NULL;
+            }
+            else
+                manifestMove(result, memContextPrior());
+        }
+
+        // If the result is NULL and the backup status has not yet been set, then the backup is unusable (invalid)
+        if (result == NULL && backupResult->status == backupValid)
+        {
+            backupResult->status = backupInvalid;
+            (*jobErrorTotal)++;
+        }
+    }
+    MEM_CONTEXT_TEMP_END();
+
+    FUNCTION_LOG_RETURN(MANIFEST, result);
+}
+
 /***********************************************************************************************************************************
 Check the history in the info files
 ***********************************************************************************************************************************/
@@ -411,7 +610,7 @@ verifyCreateArchiveIdRange(VerifyArchiveResult *archiveIdResult, StringList *wal
                 {
                     .start = strDup(walSegment),
                     .stop = strDup(walSegment),
-                    .invalidFileList = lstNewP(sizeof(VerifyInvalidFile), .comparator =  lstComparatorStr),
+                    .invalidFileList = lstNewP(sizeof(VerifyInvalidFile), .comparator = lstComparatorStr),
                 };
 
                 lstAdd(archiveIdResult->walRangeList, &walRangeNew);
@@ -470,7 +669,7 @@ verifyArchive(void *data)
                 VerifyArchiveResult archiveIdResult =
                 {
                     .archiveId = strDup(archiveId),
-                    .walRangeList = lstNewP(sizeof(VerifyWalRange), .comparator =  lstComparatorStr),
+                    .walRangeList = lstNewP(sizeof(VerifyWalRange), .comparator = lstComparatorStr),
                 };
 
                 lstAdd(jobData->archiveIdResultList, &archiveIdResult);
@@ -561,8 +760,9 @@ verifyArchive(void *data)
                         protocolCommandParamAdd(command, VARUINT64(archiveResult->pgWalInfo.size));
                         protocolCommandParamAdd(command, VARSTR(jobData->walCipherPass));
 
-                        // Assign job to result
-                        result = protocolParallelJobNew(VARSTR(filePathName), command);
+                        // Assign job to result, prepending the archiveId to the key for consistency with backup processing
+                        result = protocolParallelJobNew(
+                            VARSTR(strNewFmt("%s/%s", strZ(archiveResult->archiveId), strZ(filePathName))), command);
 
                         // Remove the file to process from the list
                         strLstRemoveIdx(jobData->walFileList, 0);
@@ -610,6 +810,229 @@ verifyArchive(void *data)
     FUNCTION_TEST_RETURN(result);
 }
 
+/***********************************************************************************************************************************
+Verify the job data backups
+***********************************************************************************************************************************/
+static ProtocolParallelJob *
+verifyBackup(void *data)
+{
+    FUNCTION_TEST_BEGIN();
+        FUNCTION_TEST_PARAM_P(VOID, data);
+    FUNCTION_TEST_END();
+
+    ProtocolParallelJob *result = NULL;
+
+    VerifyJobData *jobData = data;
+
+    // Process backup files, if any
+    while (strLstSize(jobData->backupList) > 0)
+    {
+        result = NULL;
+
+        // If result list is empty or the last processed is not equal to the backup being processed, then intialize the backup
+        // data and results
+        if (lstSize(jobData->backupResultList) == 0 ||
+            !strEq(((VerifyBackupResult *)lstGetLast(jobData->backupResultList))->backupLabel, strLstGet(jobData->backupList, 0)))
+        {
+            MEM_CONTEXT_BEGIN(lstMemContext(jobData->backupResultList))
+            {
+                VerifyBackupResult backupResultNew =
+                {
+                    .backupLabel = strDup(strLstGet(jobData->backupList, 0)),
+                    .invalidFileList = lstNewP(sizeof(VerifyInvalidFile), .comparator = lstComparatorStr),
+                };
+
+                // Add the backup to the result list
+                lstAdd(jobData->backupResultList, &backupResultNew);
+            }
+            MEM_CONTEXT_END();
+
+            // Get the result just added so it can be updated directly
+            VerifyBackupResult *backupResult = lstGetLast(jobData->backupResultList);
+
+            // If currentBackup is set (meaning the newest backup label on disk was not in the db:current section when the
+            // backup.info file was read) and this is the same label, then set inProgessBackup to true, else false.
+            // inProgressBackup may be changed in verifyManifestFile if a main backup.manifest exists since that would indicate the
+            // backup completed during the verify process.
+            bool inProgressBackup = strEq(jobData->currentBackup, backupResult->backupLabel);
+
+            // Get a usable backup manifest file
+            Manifest *manifest = verifyManifestFile(
+                backupResult, jobData->manifestCipherPass, inProgressBackup, jobData->pgHistory, &jobData->jobErrorTotal);
+
+            // If a usable backup.manifest file is not found
+            if (manifest == NULL)
+            {
+                // Remove this backup from the processing list
+                strLstRemoveIdx(jobData->backupList, 0);
+
+                // No files to process so continue to the next backup in the list
+                continue;
+            }
+            // Initialize the backup results and manifest for processing
+            else
+            {
+                // Move the manifest to the jobData for processing
+                jobData->manifest = manifestMove(manifest, jobData->memContext);
+
+                // Initialize the jobData
+                MEM_CONTEXT_BEGIN(jobData->memContext)
+                {
+                    // Get the cipher subpass used to decrypt files in the backup and initialize the file list index
+                    jobData->backupCipherPass = strDup(manifestCipherSubPass(jobData->manifest));
+                    jobData->manifestFileIdx = 0;
+                }
+                MEM_CONTEXT_END();
+
+                const ManifestData *manData = manifestData(jobData->manifest);
+
+                MEM_CONTEXT_BEGIN(lstMemContext(jobData->backupResultList))
+                {
+                    backupResult->totalFileManifest = manifestFileTotal(jobData->manifest);
+                    backupResult->backupPrior = strDup(manData->backupLabelPrior);
+                    backupResult->pgId = manData->pgId;
+                    backupResult->pgVersion = manData->pgVersion;
+                    backupResult->archiveStart = strDup(manData->archiveStart);
+                    backupResult->archiveStop = strDup(manData->archiveStop);
+                }
+                MEM_CONTEXT_END();
+            }
+        }
+
+        VerifyBackupResult *backupResult = lstGetLast(jobData->backupResultList);
+
+        // Process any files in the manifest
+        if (jobData->manifestFileIdx < manifestFileTotal(jobData->manifest))
+        {
+            do
+            {
+                const ManifestFile *fileData = manifestFile(jobData->manifest, jobData->manifestFileIdx);
+
+                String *filePathName = NULL;
+
+                // Track the files verified in order to determine when the processing of the backup is complete
+                backupResult->totalFileVerify++;
+
+                // Check if the file is referenced in a prior backup
+                if (fileData->reference != NULL)
+                {
+                    // If the prior backup is not in the result list, then that backup was never processed (likely due to the --set
+                    // option) so verify the file
+                    unsigned int backupPriorIdx = lstFindIdx(jobData->backupResultList, &fileData->reference);
+
+                    if (backupPriorIdx == LIST_NOT_FOUND)
+                    {
+                        filePathName = strNewFmt(
+                            STORAGE_REPO_BACKUP "/%s/%s%s", strZ(fileData->reference), strZ(fileData->name),
+                            strZ(compressExtStr((manifestData(jobData->manifest))->backupOptionCompressType)));
+                    }
+                    // Else the backup this file references has a result so check the processing state for the referenced backup
+                    else
+                    {
+                        VerifyBackupResult *backupResultPrior = lstGet(jobData->backupResultList, backupPriorIdx);
+
+                        // If the verify-state of the backup is not complete then verify the file
+                        if (!backupResultPrior->fileVerifyComplete)
+                        {
+                            filePathName = strNewFmt(
+                                STORAGE_REPO_BACKUP "/%s/%s%s", strZ(fileData->reference), strZ(fileData->name),
+                                strZ(compressExtStr((manifestData(jobData->manifest))->backupOptionCompressType)));
+                        }
+                        // Else skip verification
+                        else
+                        {
+                            String *priorFile = strNewFmt(
+                                "%s/%s%s", strZ(fileData->reference), strZ(fileData->name),
+                                strZ(compressExtStr((manifestData(jobData->manifest))->backupOptionCompressType)));
+
+                            unsigned int backupPriorInvalidIdx = lstFindIdx(backupResultPrior->invalidFileList, &priorFile);
+
+                            // If the file is in the invalid file list of the prior backup where it is referenced then add the file
+                            // as invalid to this backup result and set the backup result status; since already logged an error on
+                            // this file, don't log again
+                            if (backupPriorInvalidIdx != LIST_NOT_FOUND)
+                            {
+                                VerifyInvalidFile *invalidFile = lstGet(
+                                    backupResultPrior->invalidFileList, backupPriorInvalidIdx);
+                                verifyInvalidFileAdd(backupResult->invalidFileList, invalidFile->reason, invalidFile->fileName);
+                                backupResult->status = backupInvalid;
+                            }
+                            // Else the file in the prior backup was valid so increment the total valid files for this backup
+                            else
+                            {
+                                backupResult->totalFileValid++;
+                            }
+                        }
+                    }
+                }
+                // Else file is not referenced in a prior backup
+                else
+                {
+                    filePathName = strNewFmt(
+                        STORAGE_REPO_BACKUP "/%s/%s%s", strZ(backupResult->backupLabel), strZ(fileData->name),
+                        strZ(compressExtStr((manifestData(jobData->manifest))->backupOptionCompressType)));
+                }
+
+                // If constructed file name is not null then send it off for processing
+                if (filePathName != NULL)
+                {
+                    // Set up the job
+                    ProtocolCommand *command = protocolCommandNew(PROTOCOL_COMMAND_VERIFY_FILE_STR);
+                    protocolCommandParamAdd(command, VARSTR(filePathName));
+
+                    // If the checksum is not present in the manifest, it will be calculated by manifest load
+                    protocolCommandParamAdd(command, VARSTRZ(fileData->checksumSha1));
+                    protocolCommandParamAdd(command, VARUINT64(fileData->size));
+                    protocolCommandParamAdd(command, VARSTR(jobData->backupCipherPass));
+
+                    // Assign job to result (prepend backup label being processed to the key since some files are in a prior backup)
+                    result = protocolParallelJobNew(
+                        VARSTR(strNewFmt("%s/%s", strZ(backupResult->backupLabel), strZ(filePathName))), command);
+                }
+
+                // Increment the index to point to the next file
+                jobData->manifestFileIdx++;
+
+                // If this was the last file to process for this backup, then free the manifest and remove this backup from the
+                // processing list
+                if (jobData->manifestFileIdx == backupResult->totalFileManifest)
+                {
+                    manifestFree(jobData->manifest);
+                    jobData->manifest = NULL;
+                    strLstRemoveIdx(jobData->backupList, 0);
+                }
+
+                // If a job was found to be processed then break out to process it
+                if (result != NULL)
+                    break;
+            }
+            while (jobData->manifestFileIdx < backupResult->totalFileManifest);
+        }
+        else
+        {
+            // Nothing to process so report an error, free the manifest, set the status, and remove the backup from processing list
+            LOG_ERROR_FMT(
+                errorTypeCode(&FileInvalidError), "backup '%s' manifest does not contain any target files to verify",
+                strZ(backupResult->backupLabel));
+
+            jobData->jobErrorTotal++;
+
+            manifestFree(jobData->manifest);
+            jobData->manifest = NULL;
+
+            backupResult->status = backupInvalid;
+
+            strLstRemoveIdx(jobData->backupList, 0);
+        }
+
+        // If a job was found to be processed then break out to process it
+        if (result != NULL)
+            break;
+    }
+
+    FUNCTION_TEST_RETURN(result);
+}
+
 /***********************************************************************************************************************************
 Process the job data
 ***********************************************************************************************************************************/
@@ -626,7 +1049,6 @@ verifyJobCallback(void *data, unsigned int clientIdx)
     // Initialize the result
     ProtocolParallelJob *result = NULL;
 
-    // Get a new job if there are any left
     MEM_CONTEXT_TEMP_BEGIN()
     {
         VerifyJobData *jobData = data;
@@ -634,8 +1056,17 @@ verifyJobCallback(void *data, unsigned int clientIdx)
         if (!jobData->backupProcessing)
         {
             result = protocolParallelJobMove(verifyArchive(data), memContextPrior());
+
+            // Set the backupProcessing flag if the archive processing is finished so backup processing can begin immediately after
             jobData->backupProcessing = strLstSize(jobData->archiveIdList) == 0;
         }
+
+        if (jobData->backupProcessing)
+        {
+            // Only begin backup verification if the last archive result was processed
+            if (result == NULL)
+                result = protocolParallelJobMove(verifyBackup(data), memContextPrior());
+        }
     }
     MEM_CONTEXT_TEMP_END();
 
@@ -661,7 +1092,7 @@ verifyErrorMsg(VerifyResult verifyResult)
     else if (verifyResult == verifySizeInvalid)
         result = strCatZ(result, "invalid size");
     else
-        result = strCatZ(result, "invalid verify");
+        result = strCatZ(result, "invalid result");
 
     FUNCTION_TEST_RETURN(result);
 }
@@ -670,19 +1101,21 @@ verifyErrorMsg(VerifyResult verifyResult)
 Helper function to output a log message based on job result that is not verifyOk and return an error count
 ***********************************************************************************************************************************/
 static unsigned int
-verifyLogInvalidResult(VerifyResult verifyResult, unsigned int processId, String *filePathName)
+verifyLogInvalidResult(const String *fileType, VerifyResult verifyResult, unsigned int processId, const String *filePathName)
 {
     FUNCTION_TEST_BEGIN();
+        FUNCTION_TEST_PARAM(STRING, fileType);                      // Indicates archive or backup file
         FUNCTION_TEST_PARAM(ENUM, verifyResult);                    // Result code from the verifyFile() function
         FUNCTION_TEST_PARAM(UINT, processId);                       // Process Id reporting the result
         FUNCTION_TEST_PARAM(STRING, filePathName);                  // File for which results are being reported
     FUNCTION_TEST_END();
 
+    ASSERT(fileType != NULL);
     ASSERT(filePathName != NULL);
 
     // Log a warning because the WAL may have gone missing if expire came through and removed it
     // legitimately so it is not necessarily an error so the jobErrorTotal should not be incremented
-    if (verifyResult == verifyFileMissing)
+    if (strEq(fileType, STORAGE_REPO_ARCHIVE_STR) && verifyResult == verifyFileMissing)
     {
         LOG_WARN_PID_FMT(processId, "%s '%s'", strZ(verifyErrorMsg(verifyResult)), strZ(filePathName));
         FUNCTION_TEST_RETURN(0);
@@ -787,25 +1220,23 @@ verifyAddInvalidWalFile(List *walRangeList, VerifyResult fileResult, String *fil
     ASSERT(fileName != NULL);
     ASSERT(walSegment != NULL);
 
-    for (unsigned int walIdx = 0; walIdx < lstSize(walRangeList); walIdx++)
+    MEM_CONTEXT_TEMP_BEGIN()
     {
-        VerifyWalRange *walRange = lstGet(walRangeList, walIdx);
-
-        // If the WAL segment is less/equal to the stop file then it falls in this range since ranges are sorted by stop file in
-        // ascending order, therefore first one found is the range
-        if (strCmp(walRange->stop, walSegment) >= 0)
+        for (unsigned int walIdx = 0; walIdx < lstSize(walRangeList); walIdx++)
         {
-            VerifyInvalidFile invalidFile =
-            {
-                .fileName = strDup(fileName),
-                .reason = fileResult,
-            };
+            VerifyWalRange *walRange = lstGet(walRangeList, walIdx);
 
-            // Add the file to the range where it was found and exit the loop
-            lstAdd(walRange->invalidFileList, &invalidFile);
-            break;
+            // If the WAL segment is less/equal to the stop file then it falls in this range since ranges are sorted by stop file in
+            // ascending order, therefore first one found is the range
+            if (strCmp(walRange->stop, walSegment) >= 0)
+            {
+                // Add the file to the range where it was found and exit the loop
+                verifyInvalidFileAdd(walRange->invalidFileList, fileResult, fileName);
+                break;
+            }
         }
     }
+    MEM_CONTEXT_TEMP_END();
 
     FUNCTION_TEST_RETURN_VOID();
 }
@@ -814,43 +1245,122 @@ verifyAddInvalidWalFile(List *walRangeList, VerifyResult fileResult, String *fil
 Render the results of the verify command
 ***********************************************************************************************************************************/
 static String *
-verifyRender(List *archiveIdResultList)
+verifyRender(List *archiveIdResultList, List *backupResultList)
 {
     FUNCTION_TEST_BEGIN();
         FUNCTION_TEST_PARAM(LIST, archiveIdResultList);             // Result list for all archive Ids in the repo
+        FUNCTION_TEST_PARAM(LIST, backupResultList);                // Result list for all backups in the repo
     FUNCTION_TEST_END();
 
     ASSERT(archiveIdResultList != NULL);
+    ASSERT(backupResultList != NULL);
 
-    String *result = strNew("Results:\n");
+    String *result = strNew("Results:");
 
-    for (unsigned int archiveIdx = 0; archiveIdx < lstSize(archiveIdResultList); archiveIdx++)
+    // Render archive results
+    if (lstSize(archiveIdResultList) == 0)
+        strCatZ(result, "\n  archiveId: none found");
+    else
     {
-        VerifyArchiveResult *archiveIdResult = lstGet(archiveIdResultList, archiveIdx);
-        strCatFmt(
-            result, "%s  archiveId: %s, total WAL checked: %u, total valid WAL: %u", (archiveIdx > 0 ? "\n" : ""),
-            strZ(archiveIdResult->archiveId), archiveIdResult->totalWalFile, archiveIdResult->totalValidWal);
-
-        if (archiveIdResult->totalWalFile > 0)
+        for (unsigned int archiveIdx = 0; archiveIdx < lstSize(archiveIdResultList); archiveIdx++)
         {
-            unsigned int errMissing = 0;
-            unsigned int errChecksum = 0;
-            unsigned int errSize = 0;
-            unsigned int errOther = 0;
+            VerifyArchiveResult *archiveIdResult = lstGet(archiveIdResultList, archiveIdx);
+            strCatFmt(
+                result, "\n  archiveId: %s, total WAL checked: %u, total valid WAL: %u", strZ(archiveIdResult->archiveId),
+                archiveIdResult->totalWalFile, archiveIdResult->totalValidWal);
 
-            for (unsigned int walIdx = 0; walIdx < lstSize(archiveIdResult->walRangeList); walIdx++)
+            if (archiveIdResult->totalWalFile > 0)
             {
-                VerifyWalRange *walRange = lstGet(archiveIdResult->walRangeList, walIdx);
+                unsigned int errMissing = 0;
+                unsigned int errChecksum = 0;
+                unsigned int errSize = 0;
+                unsigned int errOther = 0;
 
-                LOG_DETAIL_FMT(
-                    "archiveId: %s, wal start: %s, wal stop: %s", strZ(archiveIdResult->archiveId), strZ(walRange->start),
-                    strZ(walRange->stop));
-
-                unsigned int invalidIdx = 0;
-
-                while (invalidIdx < lstSize(walRange->invalidFileList))
+                for (unsigned int walIdx = 0; walIdx < lstSize(archiveIdResult->walRangeList); walIdx++)
                 {
-                    VerifyInvalidFile *invalidFile = lstGet(walRange->invalidFileList, invalidIdx);
+                    VerifyWalRange *walRange = lstGet(archiveIdResult->walRangeList, walIdx);
+
+                    LOG_DETAIL_FMT(
+                        "archiveId: %s, wal start: %s, wal stop: %s", strZ(archiveIdResult->archiveId), strZ(walRange->start),
+                        strZ(walRange->stop));
+
+                    unsigned int invalidIdx = 0;
+
+                    while (invalidIdx < lstSize(walRange->invalidFileList))
+                    {
+                        VerifyInvalidFile *invalidFile = lstGet(walRange->invalidFileList, invalidIdx);
+
+                        if (invalidFile->reason == verifyFileMissing)
+                            errMissing++;
+                        else if (invalidFile->reason == verifyChecksumMismatch)
+                            errChecksum++;
+                        else if (invalidFile->reason == verifySizeInvalid)
+                            errSize++;
+                        else
+                            errOther++;
+
+                        invalidIdx++;
+                    }
+                }
+
+                strCatFmt(
+                    result, "\n    missing: %u, checksum invalid: %u, size invalid: %u, other: %u", errMissing, errChecksum,
+                    errSize, errOther);
+            }
+        }
+    }
+
+    // Render backup results
+    if (lstSize(backupResultList) == 0)
+        strCatZ(result, "\n  backup: none found");
+    else
+    {
+        for (unsigned int backupIdx = 0; backupIdx < lstSize(backupResultList); backupIdx++)
+        {
+            VerifyBackupResult *backupResult = lstGet(backupResultList, backupIdx);
+            String *status = NULL;
+
+            switch (backupResult->status)
+            {
+                case backupValid:
+                {
+                    status = strNew("valid");
+                    break;
+                }
+
+                case backupInvalid:
+                {
+                    status = strNew("invalid");
+                    break;
+                }
+
+                case backupMissingManifest:
+                {
+                    status = strNew("manifest missing");
+                    break;
+                }
+
+                case backupInProgress:
+                {
+                    status = strNew("in-progress");
+                    break;
+                }
+            }
+
+            strCatFmt(
+                result, "\n  backup: %s, status: %s, total files checked: %u, total valid files: %u",
+                strZ(backupResult->backupLabel), strZ(status), backupResult->totalFileVerify, backupResult->totalFileValid);
+
+            if (backupResult->totalFileVerify > 0)
+            {
+                unsigned int errMissing = 0;
+                unsigned int errChecksum = 0;
+                unsigned int errSize = 0;
+                unsigned int errOther = 0;
+
+                for (unsigned int invalidIdx = 0; invalidIdx < lstSize(backupResult->invalidFileList); invalidIdx++)
+                {
+                    VerifyInvalidFile *invalidFile = lstGet(backupResult->invalidFileList, invalidIdx);
 
                     if (invalidFile->reason == verifyFileMissing)
                         errMissing++;
@@ -860,15 +1370,12 @@ verifyRender(List *archiveIdResultList)
                         errSize++;
                     else
                         errOther++;
-
-                    invalidIdx++;
                 }
-            }
 
-            strCatFmt(
-                result,
-                "\n    missing: %u, checksum invalid: %u, size invalid: %u, other: %u",
-                errMissing, errChecksum, errSize, errOther);
+                strCatFmt(
+                    result, "\n    missing: %u, checksum invalid: %u, size invalid: %u, other: %u", errMissing, errChecksum,
+                    errSize, errOther);
+            }
         }
     }
 
@@ -940,18 +1447,20 @@ verifyProcess(unsigned int *errorTotal)
                 .walPathList = NULL,
                 .walFileList = strLstNew(),
                 .pgHistory = infoArchivePg(archiveInfo),
+                .manifestCipherPass = infoPgCipherPass(infoBackupPg(backupInfo)),
                 .walCipherPass = infoPgCipherPass(infoArchivePg(archiveInfo)),
-                .archiveIdResultList = lstNewP(sizeof(VerifyArchiveResult), .comparator =  archiveIdComparator),
+                .archiveIdResultList = lstNewP(sizeof(VerifyArchiveResult), .comparator = archiveIdComparator),
+                .backupResultList = lstNewP(sizeof(VerifyBackupResult), .comparator = lstComparatorStr),
             };
 
-            // Get a list of backups in the repo
+            // Get a list of backups in the repo sorted ascending
             jobData.backupList = strLstSort(
                 storageListP(
                     storage, STORAGE_REPO_BACKUP_STR,
                     .expression = backupRegExpP(.full = true, .differential = true, .incremental = true)),
                 sortOrderAsc);
 
-            // Get a list of archive Ids in the repo (e.g. 9.4-1, 10-2, etc) sorted by the db-id (number after the dash)
+            // Get a list of archive Ids in the repo (e.g. 9.4-1, 10-2, etc) sorted ascending by the db-id (number after the dash)
             jobData.archiveIdList = strLstSort(
                 strLstComparatorSet(
                     storageListP(storage, STORAGE_REPO_ARCHIVE_STR, .expression = STRDEF(REGEX_ARCHIVE_DIR_DB_VERSION)),
@@ -966,6 +1475,10 @@ verifyProcess(unsigned int *errorTotal)
                 if (strLstSize(jobData.archiveIdList) == 0 || strLstSize(jobData.backupList) == 0)
                     LOG_WARN_FMT("no %s exist in the repo", strLstSize(jobData.archiveIdList) == 0 ? "archives" : "backups");
 
+                // If there are no archives to process, then set the processing flag to skip to processing the backups
+                if (strLstSize(jobData.archiveIdList) == 0)
+                    jobData.backupProcessing = true;
+
                 // Set current backup if there is one and verify the archive history on disk is in the database history
                 jobData.currentBackup = verifySetBackupCheckArchive(
                     jobData.backupList, backupInfo, jobData.archiveIdList, jobData.pgHistory, &jobData.jobErrorTotal);
@@ -989,33 +1502,68 @@ verifyProcess(unsigned int *errorTotal)
                         ProtocolParallelJob *job = protocolParallelResult(parallelExec);
                         unsigned int processId = protocolParallelJobProcessId(job);
                         StringList *filePathLst = strLstNewSplit(varStr(protocolParallelJobKey(job)), FSLASH_STR);
+
+                        // Remove the result and file type identifier and recreate the path file name
+                        const String *resultId = strLstGet(filePathLst, 0);
+                        strLstRemoveIdx(filePathLst, 0);
+                        const String *fileType = strLstGet(filePathLst, 0);
                         strLstRemoveIdx(filePathLst, 0);
                         String *filePathName = strLstJoin(filePathLst, "/");
 
+                        // Initialize the result sets
                         VerifyArchiveResult *archiveIdResult = NULL;
+                        VerifyBackupResult *backupResult = NULL;
 
-                        // Find the archiveId in the list - assert if not found since this should never happen
-                        String *archiveId = strLstGet(filePathLst, 0);
-                        unsigned int index = lstFindIdx(jobData.archiveIdResultList, &archiveId);
-                        ASSERT(index != LIST_NOT_FOUND);
+                        // Get archiveId result data
+                        if (strEq(fileType, STORAGE_REPO_ARCHIVE_STR))
+                        {
+                            // Find the archiveId in the list - assert if not found since this should never happen
+                            unsigned int index = lstFindIdx(jobData.archiveIdResultList, &resultId);
+                            ASSERT(index != LIST_NOT_FOUND);
 
-                        archiveIdResult = lstGet(jobData.archiveIdResultList, index);
+                            archiveIdResult = lstGet(jobData.archiveIdResultList, index);
+                        }
+                        // Else get the backup result data
+                        else
+                        {
+                            unsigned int index = lstFindIdx(jobData.backupResultList, &resultId);
+                            ASSERT(index != LIST_NOT_FOUND);
+
+                            backupResult = lstGet(jobData.backupResultList, index);
+                        }
 
                         // The job was successful
                         if (protocolParallelJobErrorCode(job) == 0)
                         {
                             const VerifyResult verifyResult = (VerifyResult)varUIntForce(protocolParallelJobResult(job));
 
-                            if (verifyResult == verifyOk)
-                                archiveIdResult->totalValidWal++;
+                            // Update the result set for the type of file being processed
+                            if (strEq(fileType, STORAGE_REPO_ARCHIVE_STR))
+                            {
+                                if (verifyResult == verifyOk)
+                                    archiveIdResult->totalValidWal++;
+                                else
+                                {
+                                    jobData.jobErrorTotal += verifyLogInvalidResult(
+                                        fileType, verifyResult, processId, filePathName);
+
+                                    // Add invalid file to the WAL range
+                                    verifyAddInvalidWalFile(
+                                        archiveIdResult->walRangeList, verifyResult, filePathName,
+                                        strSubN(strLstGet(filePathLst, strLstSize(filePathLst) - 1), 0, WAL_SEGMENT_NAME_SIZE));
+                                }
+                            }
                             else
                             {
-                                jobData.jobErrorTotal += verifyLogInvalidResult(verifyResult, processId, filePathName);
-
-                                // Add invalid file with reason from result of verifyFile to range list
-                                verifyAddInvalidWalFile(
-                                    archiveIdResult->walRangeList, verifyResult, filePathName,
-                                    strSubN(strLstGet(filePathLst, strLstSize(filePathLst) - 1), 0, WAL_SEGMENT_NAME_SIZE));
+                                if (verifyResult == verifyOk)
+                                    backupResult->totalFileValid++;
+                                else
+                                {
+                                    jobData.jobErrorTotal += verifyLogInvalidResult(
+                                        fileType, verifyResult, processId, filePathName);
+                                    backupResult->status = backupInvalid;
+                                    verifyInvalidFileAdd(backupResult->invalidFileList, verifyResult, filePathName);
+                                }
                             }
                         }
                         // Else the job errored
@@ -1029,10 +1577,26 @@ verifyProcess(unsigned int *errorTotal)
 
                             jobData.jobErrorTotal++;
 
-                            // Add invalid file with "OtherError" reason to range list
-                            verifyAddInvalidWalFile(
-                                archiveIdResult->walRangeList, verifyOtherError, filePathName,
-                                strSubN(strLstGet(filePathLst, strLstSize(filePathLst) - 1), 0, WAL_SEGMENT_NAME_SIZE));
+                            // Add invalid file with "OtherError" reason to invalid file list
+                            if (strEq(fileType, STORAGE_REPO_ARCHIVE_STR))
+                            {
+                                // Add invalid file to the WAL range
+                                verifyAddInvalidWalFile(
+                                    archiveIdResult->walRangeList, verifyOtherError, filePathName,
+                                    strSubN(strLstGet(filePathLst, strLstSize(filePathLst) - 1), 0, WAL_SEGMENT_NAME_SIZE));
+                            }
+                            else
+                            {
+                                backupResult->status = backupInvalid;
+                                verifyInvalidFileAdd(backupResult->invalidFileList, verifyOtherError, filePathName);
+                            }
+                        }
+
+                        // Set backup verification complete for a backup if all files have run through verification
+                        if (strEq(fileType, STORAGE_REPO_BACKUP_STR) &&
+                            backupResult->totalFileVerify == backupResult->totalFileManifest)
+                        {
+                            backupResult->fileVerifyComplete = true;
                         }
 
                         // Free the job
@@ -1044,8 +1608,7 @@ verifyProcess(unsigned int *errorTotal)
                 // ??? Need to do the final reconciliation - checking backup required WAL against, valid WAL
 
                 // Report results
-                if (lstSize(jobData.archiveIdResultList) > 0)
-                    resultStr = verifyRender(jobData.archiveIdResultList);
+                resultStr = verifyRender(jobData.archiveIdResultList, jobData.backupResultList);
             }
             else
                 LOG_WARN("no archives or backups exist in the repo");
diff --git a/test/define.yaml b/test/define.yaml
index 32aab2ea1..9809a476b 100644
--- a/test/define.yaml
+++ b/test/define.yaml
@@ -712,7 +712,7 @@ unit:
 
       # ----------------------------------------------------------------------------------------------------------------------------
       - name: verify
-        total: 6
+        total: 8
         binReq: true
 
         coverage:
diff --git a/test/src/module/command/verifyTest.c b/test/src/module/command/verifyTest.c
index 7f552a688..e7b273ee0 100644
--- a/test/src/module/command/verifyTest.c
+++ b/test/src/module/command/verifyTest.c
@@ -33,68 +33,88 @@ testRun(void)
     strLstAdd(argListBase, strNewFmt("--stanza=%s", strZ(stanza)));
     strLstAdd(argListBase, strNewFmt("--repo1-path=%s/repo", testPath()));
 
+    const char *fileContents = "acefile";
+    uint64_t fileSize = 7;
+    const String *fileChecksum = STRDEF("d1cd8a7d11daa26814b93eb604e1d49ab4b43770");
+
+    #define TEST_BACKUP_DB1_94                                                                                                     \
+        "db-catalog-version=201409291\n"                                                                                           \
+        "db-control-version=942\n"                                                                                                 \
+        "db-id=1\n"                                                                                                                \
+        "db-system-id=6625592122879095702\n"                                                                                       \
+        "db-version=\"9.4\"\n"
+
+    #define TEST_BACKUP_DB2_11                                                                                                     \
+        "db-catalog-version=201707211\n"                                                                                           \
+        "db-control-version=1100\n"                                                                                                \
+        "db-id=2\n"                                                                                                                \
+        "db-system-id=6626363367545678089\n"                                                                                       \
+        "db-version=\"11\"\n"
+
+    #define TEST_BACKUP_DB1_CURRENT_FULL1                                                                                          \
+        "20181119-152138F={"                                                                                                       \
+        "\"backrest-format\":5,\"backrest-version\":\"2.28dev\","                                                                  \
+        "\"backup-archive-start\":\"000000010000000000000002\",\"backup-archive-stop\":\"000000010000000000000002\","              \
+        "\"backup-info-repo-size\":2369186,\"backup-info-repo-size-delta\":2369186,"                                               \
+        "\"backup-info-size\":20162900,\"backup-info-size-delta\":20162900,"                                                       \
+        "\"backup-timestamp-start\":1482182846,\"backup-timestamp-stop\":1482182861,\"backup-type\":\"full\","                     \
+        "\"db-id\":1,\"option-archive-check\":true,\"option-archive-copy\":false,\"option-backup-standby\":false,"                 \
+        "\"option-checksum-page\":true,\"option-compress\":true,\"option-hardlink\":false,\"option-online\":true}\n"
+
+    #define TEST_BACKUP_DB1_CURRENT_FULL2                                                                                          \
+        "20181119-152800F={"                                                                                                       \
+        "\"backrest-format\":5,\"backrest-version\":\"2.08dev\","                                                                  \
+        "\"backup-info-repo-size\":2369186,\"backup-info-repo-size-delta\":2369186,"                                               \
+        "\"backup-info-size\":20162900,\"backup-info-size-delta\":20162900,"                                                       \
+        "\"backup-timestamp-start\":1542640898,\"backup-timestamp-stop\":1542640911,\"backup-type\":\"full\","                     \
+        "\"db-id\":1,\"option-archive-check\":true,\"option-archive-copy\":false,\"option-backup-standby\":false,"                 \
+        "\"option-checksum-page\":true,\"option-compress\":true,\"option-hardlink\":false,\"option-online\":true}\n"
+
+    #define TEST_BACKUP_DB1_CURRENT_FULL3                                                                                          \
+        "20181119-152900F={"                                                                                                       \
+        "\"backrest-format\":5,\"backrest-version\":\"2.08dev\","                                                                  \
+        "\"backup-archive-start\":\"000000010000000000000004\",\"backup-archive-stop\":\"000000010000000000000004\","              \
+        "\"backup-info-repo-size\":2369186,\"backup-info-repo-size-delta\":2369186,"                                               \
+        "\"backup-info-size\":20162900,\"backup-info-size-delta\":20162900,"                                                       \
+        "\"backup-timestamp-start\":1542640898,\"backup-timestamp-stop\":1542640911,\"backup-type\":\"full\","                     \
+        "\"db-id\":1,\"option-archive-check\":true,\"option-archive-copy\":false,\"option-backup-standby\":false,"                 \
+        "\"option-checksum-page\":true,\"option-compress\":true,\"option-hardlink\":false,\"option-online\":true}\n"
+
+    #define TEST_BACKUP_DB1_HISTORY                                                                                                \
+        "1={\"db-catalog-version\":201409291,\"db-control-version\":942,\"db-system-id\":6625592122879095702,"                     \
+            "\"db-version\":\"9.4\"}"
+
+    #define TEST_BACKUP_DB2_HISTORY                                                                                                \
+        "2={\"db-catalog-version\":201707211,\"db-control-version\":1100,\"db-system-id\":6626363367545678089,"                    \
+            "\"db-version\":\"11\"}"
+
     String *backupInfoContent = strNewFmt(
         "[backup:current]\n"
-        "20181119-152138F={"
-        "\"backrest-format\":5,\"backrest-version\":\"2.28dev\","
-        "\"backup-archive-start\":\"000000010000000000000002\",\"backup-archive-stop\":\"000000010000000000000002\","
-        "\"backup-info-repo-size\":2369186,\"backup-info-repo-size-delta\":2369186,"
-        "\"backup-info-size\":20162900,\"backup-info-size-delta\":20162900,"
-        "\"backup-timestamp-start\":1482182846,\"backup-timestamp-stop\":1482182861,\"backup-type\":\"full\","
-        "\"db-id\":1,\"option-archive-check\":true,\"option-archive-copy\":false,\"option-backup-standby\":false,"
-        "\"option-checksum-page\":true,\"option-compress\":true,\"option-hardlink\":false,\"option-online\":true}\n"
+        TEST_BACKUP_DB1_CURRENT_FULL1
         "\n"
         "[db]\n"
-        "db-catalog-version=201409291\n"
-        "db-control-version=942\n"
-        "db-id=1\n"
-        "db-system-id=6625592122879095702\n"
-        "db-version=\"9.4\"\n"
+        TEST_BACKUP_DB1_94
         "\n"
         "[db:history]\n"
-        "1={\"db-catalog-version\":201409291,\"db-control-version\":942,\"db-system-id\":6625592122879095702,"
-            "\"db-version\":\"9.4\"}");
+        TEST_BACKUP_DB1_HISTORY
+        );
 
     const Buffer *backupInfoBase = harnessInfoChecksumZ(strZ(backupInfoContent));
 
     String *backupInfoMultiHistoryContent = strNewFmt(
         "[backup:current]\n"
-        "20181119-152138F={"
-        "\"backrest-format\":5,\"backrest-version\":\"2.08dev\","
-        "\"backup-archive-start\":\"000000010000000000000002\",\"backup-archive-stop\":\"000000010000000000000002\","
-        "\"backup-info-repo-size\":2369186,\"backup-info-repo-size-delta\":2369186,"
-        "\"backup-info-size\":20162900,\"backup-info-size-delta\":20162900,"
-        "\"backup-timestamp-start\":1542640898,\"backup-timestamp-stop\":1542640911,\"backup-type\":\"full\","
-        "\"db-id\":1,\"option-archive-check\":true,\"option-archive-copy\":false,\"option-backup-standby\":false,"
-        "\"option-checksum-page\":true,\"option-compress\":true,\"option-hardlink\":false,\"option-online\":true}\n"
-        "20181119-152800F={"
-        "\"backrest-format\":5,\"backrest-version\":\"2.08dev\","
-        "\"backup-info-repo-size\":2369186,\"backup-info-repo-size-delta\":2369186,"
-        "\"backup-info-size\":20162900,\"backup-info-size-delta\":20162900,"
-        "\"backup-timestamp-start\":1542640898,\"backup-timestamp-stop\":1542640911,\"backup-type\":\"full\","
-        "\"db-id\":1,\"option-archive-check\":true,\"option-archive-copy\":false,\"option-backup-standby\":false,"
-        "\"option-checksum-page\":true,\"option-compress\":true,\"option-hardlink\":false,\"option-online\":true}\n"
-        "20181119-152900F={"
-        "\"backrest-format\":5,\"backrest-version\":\"2.08dev\","
-        "\"backup-archive-start\":\"000000010000000000000004\",\"backup-archive-stop\":\"000000010000000000000004\","
-        "\"backup-info-repo-size\":2369186,\"backup-info-repo-size-delta\":2369186,"
-        "\"backup-info-size\":20162900,\"backup-info-size-delta\":20162900,"
-        "\"backup-timestamp-start\":1542640898,\"backup-timestamp-stop\":1542640911,\"backup-type\":\"full\","
-        "\"db-id\":1,\"option-archive-check\":true,\"option-archive-copy\":false,\"option-backup-standby\":false,"
-        "\"option-checksum-page\":true,\"option-compress\":true,\"option-hardlink\":false,\"option-online\":true}\n"
+        TEST_BACKUP_DB1_CURRENT_FULL1
+        TEST_BACKUP_DB1_CURRENT_FULL2
+        TEST_BACKUP_DB1_CURRENT_FULL3
         "\n"
         "[db]\n"
-        "db-catalog-version=201707211\n"
-        "db-control-version=1100\n"
-        "db-id=2\n"
-        "db-system-id=6626363367545678089\n"
-        "db-version=\"11\"\n"
+        TEST_BACKUP_DB2_11
         "\n"
         "[db:history]\n"
-        "1={\"db-catalog-version\":201409291,\"db-control-version\":942,\"db-system-id\":6625592122879095702,"
-            "\"db-version\":\"9.4\"}\n"
-        "2={\"db-catalog-version\":201707211,\"db-control-version\":1100,\"db-system-id\":6626363367545678089,"
-            "\"db-version\":\"11\"}");
+        TEST_BACKUP_DB1_HISTORY
+        "\n"
+        TEST_BACKUP_DB2_HISTORY
+        );
 
     const Buffer *backupInfoMultiHistoryBase = harnessInfoChecksumZ(strZ(backupInfoMultiHistoryContent));
 
@@ -121,6 +141,288 @@ testRun(void)
 
     const Buffer *archiveInfoMultiHistoryBase = harnessInfoChecksumZ(strZ(archiveInfoMultiHistoryContent));
 
+    #define TEST_MANIFEST_HEADER                                                                                                   \
+        "[backup]\n"                                                                                                               \
+        "backup-label=null\n"                                                                                                      \
+        "backup-timestamp-copy-start=0\n"                                                                                          \
+        "backup-timestamp-start=0\n"                                                                                               \
+        "backup-timestamp-stop=0\n"                                                                                                \
+        "backup-type=\"full\"\n"
+
+    #define TEST_MANIFEST_DB_92                                                                                                    \
+        "\n"                                                                                                                       \
+        "[backup:db]\n"                                                                                                            \
+        "db-catalog-version=201204301\n"                                                                                           \
+        "db-control-version=922\n"                                                                                                 \
+        "db-id=1\n"                                                                                                                \
+        "db-system-id=6625592122879095702\n"                                                                                       \
+        "db-version=\"9.2\"\n"
+
+    #define TEST_MANIFEST_DB_94                                                                                                    \
+        "\n"                                                                                                                       \
+        "[backup:db]\n"                                                                                                            \
+        "db-catalog-version=201409291\n"                                                                                           \
+        "db-control-version=942\n"                                                                                                 \
+        "db-id=1\n"                                                                                                                \
+        "db-system-id=6625592122879095702\n"                                                                                       \
+        "db-version=\"9.4\"\n"
+
+    #define TEST_MANIFEST_OPTION_ALL                                                                                               \
+        "\n"                                                                                                                       \
+        "[backup:option]\n"                                                                                                        \
+        "option-archive-check=false\n"                                                                                             \
+        "option-archive-copy=false\n"                                                                                              \
+        "option-checksum-page=false\n"                                                                                             \
+        "option-compress=false\n"                                                                                                  \
+        "option-compress-type=\"none\"\n"                                                                                          \
+        "option-hardlink=false\n"                                                                                                  \
+        "option-online=false\n"
+
+    #define TEST_MANIFEST_OPTION_ARCHIVE_TRUE                                                                                      \
+        "\n"                                                                                                                       \
+        "[backup:option]\n"                                                                                                        \
+        "option-archive-check=true\n"                                                                                              \
+        "option-archive-copy=true\n"
+
+    #define TEST_MANIFEST_TARGET                                                                                                   \
+        "\n"                                                                                                                       \
+        "[backup:target]\n"                                                                                                        \
+        "pg_data={\"path\":\"/pg/base\",\"type\":\"path\"}\n"
+
+    #define TEST_MANIFEST_DB                                                                                                       \
+        "\n"                                                                                                                       \
+        "[db]\n"                                                                                                                   \
+        "postgres={\"db-id\":12173,\"db-last-system-id\":12168}\n"
+
+    #define TEST_MANIFEST_FILE                                                                                                     \
+        "\n"                                                                                                                       \
+        "[target:file]\n"                                                                                                          \
+        "pg_data/PG_VERSION={\"checksum\":\"184473f470864e067ee3a22e64b47b0a1c356f29\",\"master\":true"                            \
+            ",\"size\":4,\"timestamp\":1565282114}\n"
+
+    #define TEST_MANIFEST_FILE_DEFAULT                                                                                             \
+        "\n"                                                                                                                       \
+        "[target:file:default]\n"                                                                                                  \
+        "group=\"group1\"\n"                                                                                                       \
+        "master=false\n"                                                                                                           \
+        "mode=\"0600\"\n"                                                                                                          \
+        "user=\"user1\"\n"
+
+    #define TEST_MANIFEST_LINK                                                                                                     \
+        "\n"                                                                                                                       \
+        "[target:link]\n"                                                                                                          \
+        "pg_data/pg_stat={\"destination\":\"../pg_stat\"}\n"
+
+    #define TEST_MANIFEST_LINK_DEFAULT                                                                                             \
+        "\n"                                                                                                                       \
+        "[target:link:default]\n"                                                                                                  \
+        "group=\"group1\"\n"                                                                                                       \
+        "user=false\n"
+
+    #define TEST_MANIFEST_PATH                                                                                                     \
+        "\n"                                                                                                                       \
+        "[target:path]\n"                                                                                                          \
+        "pg_data={\"user\":\"user1\"}\n"                                                                                           \
+
+    #define TEST_MANIFEST_PATH_DEFAULT                                                                                             \
+        "\n"                                                                                                                       \
+        "[target:path:default]\n"                                                                                                  \
+        "group=false\n"                                                                                                            \
+        "mode=\"0700\"\n"                                                                                                          \
+        "user=\"user1\"\n"
+
+    // *****************************************************************************************************************************
+    if (testBegin("verifyManifestFile()"))
+    {
+        // Load Parameters
+        StringList *argList = strLstDup(argListBase);
+        harnessCfgLoad(cfgCmdVerify, argList);
+
+        const Buffer *contentLoad = harnessInfoChecksumZ
+        (
+            TEST_MANIFEST_HEADER
+            TEST_MANIFEST_DB_92
+            TEST_MANIFEST_OPTION_ALL
+            TEST_MANIFEST_TARGET
+            TEST_MANIFEST_DB
+            TEST_MANIFEST_FILE
+            TEST_MANIFEST_FILE_DEFAULT
+            TEST_MANIFEST_LINK
+            TEST_MANIFEST_LINK_DEFAULT
+            TEST_MANIFEST_PATH
+            TEST_MANIFEST_PATH_DEFAULT
+        );
+
+        Manifest *manifest = NULL;
+        String *backupLabel = strNew("20181119-152138F");
+        String *manifestFile = strNewFmt("%s/%s/" BACKUP_MANIFEST_FILE, strZ(backupStanzaPath), strZ(backupLabel));
+        String *manifestFileCopy = strNewFmt("%s" INFO_COPY_EXT, strZ(manifestFile));
+        unsigned int jobErrorTotal = 0;
+        VerifyBackupResult backupResult = {.backupLabel = strDup(backupLabel)};
+
+        InfoArchive *archiveInfo = NULL;
+        TEST_ASSIGN(archiveInfo, infoArchiveNewLoad(ioBufferReadNew(archiveInfoBase)), "archive.info");
+        InfoPg *infoPg = infoArchivePg(archiveInfo);
+
+        //--------------------------------------------------------------------------------------------------------------------------
+        TEST_TITLE("manifest.copy exists, no manifest main, manifest db version not in history, not current db");
+
+        TEST_RESULT_VOID(
+            storagePutP(storageNewWriteP(storageTest, manifestFile), contentLoad), "write manifest db section mismatch");
+
+        backupResult.status = backupValid;
+        TEST_ASSIGN(manifest, verifyManifestFile(&backupResult, NULL, false, infoPg, &jobErrorTotal), "verify manifest");
+        TEST_RESULT_PTR(manifest, NULL, "manifest not set - pg version mismatch");
+        TEST_RESULT_UINT(backupResult.status, backupInvalid, "manifest unusable - backup invalid");
+        harnessLogResult(
+            strZ(strNewFmt(
+            "P00   WARN: unable to open missing file '%s/%s/%s/" BACKUP_MANIFEST_FILE INFO_COPY_EXT "' for read\n"
+            "P00  ERROR: [028]: '%s' may not be recoverable - PG data (id 1, version 9.2, system-id 6625592122879095702) is not "
+                "in the backup.info history, skipping",
+            testPath(), strZ(backupStanzaPath), strZ(backupLabel), strZ(backupLabel))));
+
+        //--------------------------------------------------------------------------------------------------------------------------
+        TEST_TITLE("rerun test with db-system-id invalid and no main");
+
+        contentLoad = harnessInfoChecksumZ
+        (
+            TEST_MANIFEST_HEADER
+            "\n"
+            "[backup:db]\n"
+            "db-catalog-version=201409291\n"
+            "db-control-version=942\n"
+            "db-id=1\n"
+            "db-system-id=0\n"
+            "db-version=\"9.4\"\n"
+            TEST_MANIFEST_OPTION_ALL
+            TEST_MANIFEST_TARGET
+            TEST_MANIFEST_DB
+            TEST_MANIFEST_FILE
+            TEST_MANIFEST_FILE_DEFAULT
+            TEST_MANIFEST_LINK
+            TEST_MANIFEST_LINK_DEFAULT
+            TEST_MANIFEST_PATH
+            TEST_MANIFEST_PATH_DEFAULT
+        );
+
+        TEST_RESULT_VOID(storageRemoveP(storageTest, manifestFile), "remove main manifest");
+        TEST_RESULT_VOID(
+            storagePutP(storageNewWriteP(storageTest, manifestFileCopy), contentLoad), "write manifest copy invalid system-id");
+
+        backupResult.status = backupValid;
+        TEST_ASSIGN(manifest, verifyManifestFile(&backupResult, NULL, false, infoPg, &jobErrorTotal), "verify manifest");
+        TEST_RESULT_PTR(manifest, NULL, "manifest not set - pg system-id mismatch");
+        TEST_RESULT_UINT(backupResult.status, backupInvalid, "manifest unusable - backup invalid");
+        harnessLogResult(
+            strZ(strNewFmt(
+            "P00   WARN: unable to open missing file '%s/%s/%s/" BACKUP_MANIFEST_FILE "' for read\n"
+            "P00   WARN: %s/backup.manifest is missing or unusable, using copy\n"
+            "P00  ERROR: [028]: '%s' may not be recoverable - PG data (id 1, version 9.4, system-id 0) is not "
+                "in the backup.info history, skipping",
+            testPath(), strZ(backupStanzaPath), strZ(backupLabel), strZ(backupLabel), strZ(backupLabel))));
+
+        //--------------------------------------------------------------------------------------------------------------------------
+        TEST_TITLE("rerun copy test with db-id invalid");
+
+        contentLoad = harnessInfoChecksumZ
+        (
+            TEST_MANIFEST_HEADER
+            "\n"
+            "[backup:db]\n"
+            "db-catalog-version=201409291\n"
+            "db-control-version=942\n"
+            "db-id=0\n"
+            "db-system-id=6625592122879095702\n"
+            "db-version=\"9.4\"\n"
+            TEST_MANIFEST_OPTION_ALL
+            TEST_MANIFEST_TARGET
+            TEST_MANIFEST_DB
+            TEST_MANIFEST_FILE
+            TEST_MANIFEST_FILE_DEFAULT
+            TEST_MANIFEST_LINK
+            TEST_MANIFEST_LINK_DEFAULT
+            TEST_MANIFEST_PATH
+            TEST_MANIFEST_PATH_DEFAULT
+        );
+
+        TEST_RESULT_VOID(
+            storagePutP(storageNewWriteP(storageTest, manifestFileCopy), contentLoad), "write manifest copy invalid db-id");
+
+        backupResult.status = backupValid;
+        TEST_ASSIGN(manifest, verifyManifestFile(&backupResult, NULL, false, infoPg, &jobErrorTotal), "verify manifest");
+        TEST_RESULT_PTR(manifest, NULL, "manifest not set - pg db-id mismatch");
+        TEST_RESULT_UINT(backupResult.status, backupInvalid, "manifest unusable - backup invalid");
+        harnessLogResult(
+            strZ(strNewFmt(
+            "P00   WARN: unable to open missing file '%s/%s/%s/" BACKUP_MANIFEST_FILE "' for read\n"
+            "P00   WARN: %s/backup.manifest is missing or unusable, using copy\n"
+            "P00  ERROR: [028]: '%s' may not be recoverable - PG data (id 0, version 9.4, system-id 6625592122879095702) is not "
+                "in the backup.info history, skipping",
+            testPath(), strZ(backupStanzaPath), strZ(backupLabel), strZ(backupLabel), strZ(backupLabel))));
+
+        //--------------------------------------------------------------------------------------------------------------------------
+        TEST_TITLE("missing main manifest, errored copy");
+
+        backupResult.status = backupValid;
+        contentLoad = BUFSTRDEF(
+            "[backrest]\n"
+            "backrest-checksum=\"BOGUS\"\n"
+            "backrest-format=5\n"
+            "backrest-version=\"2.28\"\n");
+
+        TEST_RESULT_VOID(
+            storagePutP(storageNewWriteP(storageTest, manifestFileCopy), contentLoad), "write invalid manifest copy");
+        TEST_ASSIGN(manifest, verifyManifestFile(&backupResult, NULL, false, infoPg, &jobErrorTotal), "verify manifest");
+        TEST_RESULT_UINT(backupResult.status, backupInvalid, "manifest unusable - backup invalid");
+        harnessLogResult(
+            strZ(strNewFmt(
+            "P00   WARN: unable to open missing file '%s/%s/%s/" BACKUP_MANIFEST_FILE "' for read\n"
+            "P00   WARN: invalid checksum, actual 'e056f784a995841fd4e2802b809299b8db6803a2' but expected 'BOGUS' "
+            STORAGE_REPO_BACKUP "/%s/" BACKUP_MANIFEST_FILE INFO_COPY_EXT, testPath(), strZ(backupStanzaPath), strZ(backupLabel),
+            strZ(backupLabel))));
+
+        //--------------------------------------------------------------------------------------------------------------------------
+        TEST_TITLE("current backup true");
+
+        TEST_RESULT_VOID(
+            storagePutP(storageNewWriteP(storageTest, manifestFile), contentLoad), "write invalid manifest");
+
+        TEST_ASSIGN(manifest, verifyManifestFile(&backupResult, NULL, true, infoPg, &jobErrorTotal), "verify manifest");
+        TEST_RESULT_PTR(manifest, NULL, "manifest not set");
+        TEST_RESULT_UINT(backupResult.status, backupInvalid, "manifest unusable - backup invalid");
+        harnessLogResult(
+            strZ(strNewFmt(
+            "P00   WARN: invalid checksum, actual 'e056f784a995841fd4e2802b809299b8db6803a2' but expected 'BOGUS' "
+            STORAGE_REPO_BACKUP "/%s/" BACKUP_MANIFEST_FILE "\n"
+            "P00   WARN: invalid checksum, actual 'e056f784a995841fd4e2802b809299b8db6803a2' but expected 'BOGUS' "
+            STORAGE_REPO_BACKUP "/%s/" BACKUP_MANIFEST_FILE INFO_COPY_EXT, strZ(backupLabel), strZ(backupLabel))));
+
+        // Write a valid manifest with a manifest copy that is invalid
+        contentLoad = harnessInfoChecksumZ
+        (
+            TEST_MANIFEST_HEADER
+            TEST_MANIFEST_DB_94
+            TEST_MANIFEST_OPTION_ALL
+            TEST_MANIFEST_TARGET
+            TEST_MANIFEST_DB
+            TEST_MANIFEST_FILE
+            TEST_MANIFEST_FILE_DEFAULT
+            TEST_MANIFEST_LINK
+            TEST_MANIFEST_LINK_DEFAULT
+            TEST_MANIFEST_PATH
+            TEST_MANIFEST_PATH_DEFAULT
+        );
+
+        TEST_RESULT_VOID(
+            storagePutP(storageNewWriteP(storageTest, manifestFile), contentLoad), "write valid manifest");
+
+        backupResult.status = backupValid;
+        TEST_ASSIGN(manifest, verifyManifestFile(&backupResult, NULL, true, infoPg, &jobErrorTotal), "verify manifest");
+        TEST_RESULT_PTR_NE(manifest, NULL, "manifest set");
+        TEST_RESULT_UINT(backupResult.status, backupValid, "manifest usable");
+        harnessLogResult(strZ(strNewFmt("P00   WARN: backup '%s' manifest.copy does not match manifest", strZ(backupLabel))));
+    }
+
     // *****************************************************************************************************************************
     if (testBegin("verifyCreateArchiveIdRange()"))
     {
@@ -378,15 +680,6 @@ testRun(void)
 
         unsigned int errTotal = 0;
 
-        TEST_RESULT_STR_Z(
-            verifySetBackupCheckArchive(
-                strLstNew(), backupInfo, strLstNew(), pgHistory, &errTotal), NULL, "no archives or backups");
-        TEST_RESULT_UINT(errTotal, 0, "no error");
-        TEST_RESULT_STR_Z(
-            verifySetBackupCheckArchive(
-                backupList, backupInfo, archiveIdList, pgHistory, &errTotal), NULL, "no current backup, no missing archive");
-        TEST_RESULT_UINT(errTotal, 0, "no error");
-
         // Add backup to end of list
         strLstAddZ(backupList, "20181119-153000F");
         strLstAddZ(archiveIdList, "12-3");
@@ -408,13 +701,17 @@ testRun(void)
         //--------------------------------------------------------------------------------------------------------------------------
         TEST_TITLE("verifyLogInvalidResult() - missing file");
 
-        TEST_RESULT_UINT(verifyLogInvalidResult(verifyFileMissing, 0, strNew("missingfilename")), 0, "file missing message");
+        TEST_RESULT_UINT(
+            verifyLogInvalidResult(STORAGE_REPO_ARCHIVE_STR, verifyFileMissing, 0, strNew("missingfilename")),
+            0, "file missing message");
         harnessLogResult("P00   WARN: file missing 'missingfilename'");
 
         //--------------------------------------------------------------------------------------------------------------------------
         TEST_TITLE("verifyRender() - missing file, empty invalidList");
 
         List *archiveIdResultList = lstNewP(sizeof(VerifyArchiveResult), .comparator =  archiveIdComparator);
+        List *backupResultList = lstNewP(sizeof(VerifyBackupResult), .comparator = lstComparatorStr);
+
         VerifyArchiveResult archiveIdResult =
         {
             .archiveId = strNew("9.6-1"),
@@ -431,25 +728,40 @@ testRun(void)
         lstAdd(archiveIdResult.walRangeList, &walRange);
         lstAdd(archiveIdResultList, &archiveIdResult);
         TEST_RESULT_STR_Z(
-            verifyRender(archiveIdResultList),
+            verifyRender(archiveIdResultList, backupResultList),
             "Results:\n"
             "  archiveId: 9.6-1, total WAL checked: 1, total valid WAL: 0\n"
-            "    missing: 0, checksum invalid: 0, size invalid: 0, other: 0", "no invalid file list");
+            "    missing: 0, checksum invalid: 0, size invalid: 0, other: 0\n"
+            "  backup: none found", "archive: no invalid file list");
 
         VerifyInvalidFile invalidFile =
         {
             .fileName = strNew("file"),
             .reason = verifyFileMissing,
         };
-
         lstAdd(walRange.invalidFileList, &invalidFile);
+
+        VerifyBackupResult backupResult =
+        {
+            .backupLabel = strNew("test-backup-label"),
+            .status = backupInvalid,
+            .totalFileVerify = 1,
+            .invalidFileList = lstNewP(sizeof(VerifyInvalidFile), .comparator =  lstComparatorStr),
+        };
+        lstAdd(backupResult.invalidFileList, &invalidFile);
+        lstAdd(backupResultList, &backupResult);
+
         TEST_RESULT_STR_Z(
-            verifyRender(archiveIdResultList),
+            verifyRender(archiveIdResultList, backupResultList),
             "Results:\n"
             "  archiveId: 9.6-1, total WAL checked: 1, total valid WAL: 0\n"
-            "    missing: 1, checksum invalid: 0, size invalid: 0, other: 0", "file missing");
+            "    missing: 1, checksum invalid: 0, size invalid: 0, other: 0\n"
+            "  backup: test-backup-label, status: invalid, total files checked: 1, total valid files: 0\n"
+            "    missing: 1, checksum invalid: 0, size invalid: 0, other: 0", "archive file missing, backup file missing");
+
+        //--------------------------------------------------------------------------------------------------------------------------
+        TEST_TITLE("verifyAddInvalidWalFile() - file missing (coverage test)");
 
-        // Coverage test
         TEST_RESULT_VOID(
             verifyAddInvalidWalFile(archiveIdResult.walRangeList, verifyFileMissing, strNew("test"), strNew("3")), "coverage test");
     }
@@ -461,20 +773,6 @@ testRun(void)
         StringList *argList = strLstDup(argListBase);
         harnessCfgLoad(cfgCmdVerify, argList);
 
-        //--------------------------------------------------------------------------------------------------------------------------
-        TEST_TITLE("neither backup nor archive info files exist");
-
-        TEST_ERROR(cmdVerify(), RuntimeError, "2 fatal errors encountered, see log for details");
-        harnessLogResult(
-            strZ(strNewFmt(
-            "P00   WARN: unable to open missing file '%s/%s/backup.info' for read\n"
-            "P00   WARN: unable to open missing file '%s/%s/backup.info.copy' for read\n"
-            "P00  ERROR: [029]: No usable backup.info file\n"
-            "P00   WARN: unable to open missing file '%s/%s/archive.info' for read\n"
-            "P00   WARN: unable to open missing file '%s/%s/archive.info.copy' for read\n"
-            "P00  ERROR: [029]: No usable archive.info file", testPath(), strZ(backupStanzaPath), testPath(),
-            strZ(backupStanzaPath), testPath(), strZ(archiveStanzaPath), testPath(), strZ(archiveStanzaPath))));
-
         //--------------------------------------------------------------------------------------------------------------------------
         TEST_TITLE("backup.info invalid checksum, neither backup copy nor archive infos exist");
 
@@ -575,34 +873,6 @@ testRun(void)
             "P00   WARN: unable to open missing file '%s/%s/backup.info.copy' for read\n"
             "P00  ERROR: [029]: No usable backup.info file", testPath(), strZ(backupStanzaPath), testPath(),
             strZ(backupStanzaPath))));
-
-        //--------------------------------------------------------------------------------------------------------------------------
-        TEST_TITLE("backup.info.copy valid, archive.info and copy valid, present but empty backup");
-
-        TEST_RESULT_VOID(
-            storagePutP(storageNewWriteP(storageTest, backupInfoFileName), backupInfoMultiHistoryBase),
-            "write valid backup.info");
-        TEST_RESULT_VOID(
-            storagePutP(storageNewWriteP(storageTest, backupInfoFileNameCopy), backupInfoMultiHistoryBase),
-            "write valid backup.info.copy");
-        TEST_RESULT_VOID(
-            storagePathCreateP(storageTest, strNewFmt("%s/20200810-171426F", strZ(backupStanzaPath))),
-            "create empty backup label path");
-        TEST_RESULT_VOID(cmdVerify(), "no archives, empty backup label path");
-        harnessLogResult("P00   WARN: no archives exist in the repo");
-
-        //--------------------------------------------------------------------------------------------------------------------------
-        TEST_TITLE("backup.info.copy valid, archive.info and copy valid, present but empty backup, empty archive");
-
-        TEST_RESULT_VOID(
-            storagePathCreateP(storageTest, strNewFmt("%s/9.4-1", strZ(archiveStanzaPath))),
-            "create empty path for archiveId");
-
-        TEST_RESULT_VOID(cmdVerify(), "no jobs - empty archive id and backup label paths");
-        harnessLogResult(
-            "P00   WARN: archive path '9.4-1' is empty\n"
-            "P00   INFO: Results:\n"
-            "              archiveId: 9.4-1, total WAL checked: 0, total valid WAL: 0");
     }
 
     // *****************************************************************************************************************************
@@ -619,19 +889,12 @@ testRun(void)
         TEST_RESULT_VOID(storagePutP(storageNewWriteP(storageRepoWrite(), filePathName), BUFSTRDEF("")), "put zero-sized file");
         TEST_RESULT_UINT(verifyFile(filePathName, STRDEF(HASH_TYPE_SHA1_ZERO), 0, NULL), verifyOk, "file ok");
 
-        const char *fileContents = "acefile";
-        uint64_t fileSize = 7;
-        const String *checksum = STRDEF("d1cd8a7d11daa26814b93eb604e1d49ab4b43770");
-
         TEST_RESULT_VOID(storagePutP(storageNewWriteP(storageRepoWrite(), filePathName), BUFSTRZ(fileContents)), "put file");
 
-        TEST_RESULT_UINT(verifyFile(filePathName, checksum, fileSize, NULL), verifyOk, "file size ok");
-        TEST_RESULT_UINT(verifyFile(filePathName, checksum, 0, NULL), verifySizeInvalid, "file size invalid");
-        TEST_RESULT_UINT(
-            verifyFile(filePathName, strNew("badchecksum"), fileSize, NULL), verifyChecksumMismatch, "file checksum mismatch");
+        TEST_RESULT_UINT(verifyFile(filePathName, fileChecksum, 0, NULL), verifySizeInvalid, "file size invalid");
         TEST_RESULT_UINT(
             verifyFile(
-                strNewFmt(STORAGE_REPO_ARCHIVE "/missingFile"), checksum, 0, NULL), verifyFileMissing, "file missing");
+                strNewFmt(STORAGE_REPO_ARCHIVE "/missingFile"), fileChecksum, 0, NULL), verifyFileMissing, "file missing");
 
         // Create a compressed encrypted repo file
         filePathName = strNew(STORAGE_REPO_BACKUP "/testfile.gz");
@@ -642,7 +905,7 @@ testRun(void)
         TEST_RESULT_VOID(storagePutP(write, BUFSTRZ(fileContents)), "write encrypted, compressed file");
 
         TEST_RESULT_UINT(
-            verifyFile(filePathName, checksum, fileSize, strNew("pass")), verifyOk, "file encrypted compressed ok");
+            verifyFile(filePathName, fileChecksum, fileSize, strNew("pass")), verifyOk, "file encrypted compressed ok");
         TEST_RESULT_UINT(
             verifyFile(
                 filePathName, strNew("badchecksum"), fileSize, strNew("pass")), verifyChecksumMismatch,
@@ -660,7 +923,7 @@ testRun(void)
 
         VariantList *paramList = varLstNew();
         varLstAdd(paramList, varNewStr(filePathName));
-        varLstAdd(paramList, varNewStr(checksum));
+        varLstAdd(paramList, varNewStr(fileChecksum));
         varLstAdd(paramList, varNewUInt64(fileSize));
         varLstAdd(paramList, varNewStrZ("pass"));
 
@@ -672,7 +935,7 @@ testRun(void)
     }
 
     // *****************************************************************************************************************************
-    if (testBegin("cmdVerify(), verifyProcess()"))
+    if (testBegin("cmdVerify(), verifyProcess() - errors"))
     {
         //--------------------------------------------------------------------------------------------------------------------------
         StringList *argList = strLstDup(argListBase);
@@ -697,18 +960,14 @@ testRun(void)
             storagePutP(storageNewWriteP(storageTest, backupInfoFileName),
                 harnessInfoChecksumZ(
                     "[db]\n"
-                    "db-catalog-version=201707211\n"
-                    "db-control-version=1100\n"
-                    "db-id=2\n"
-                    "db-system-id=6626363367545678089\n"
-                    "db-version=\"11\"\n"
+                    TEST_BACKUP_DB2_11
                     "\n"
                     "[db:history]\n"
-                    "1={\"db-catalog-version\":201409291,\"db-control-version\":942,\"db-system-id\":6625592122879095702,"
-                        "\"db-version\":\"9.4\"}\n"
-                    "2={\"db-catalog-version\":201707211,\"db-control-version\":1100,\"db-system-id\":6626363367545678089,"
-                        "\"db-version\":\"11\"}")),
-            "put backup.info files");
+                    TEST_BACKUP_DB1_HISTORY
+                    "\n"
+                    TEST_BACKUP_DB2_HISTORY
+                    )),
+            "put backup.info files - no current backups");
         storageCopy(storageNewReadP(storageTest, backupInfoFileName), storageNewWriteP(storageTest, backupInfoFileNameCopy));
 
         //--------------------------------------------------------------------------------------------------------------------------
@@ -743,13 +1002,14 @@ testRun(void)
 
         TEST_ERROR(cmdVerify(), RuntimeError, "1 fatal errors encountered, see log for details");
         harnessLogResult(
-            strZ(strNewFmt(
+            strZ(strNew(
                 "P00   WARN: no backups exist in the repo\n"
                 "P00  ERROR: [028]: duplicate WAL '000000020000000700000FFE' for '11-2' exists, skipping\n"
                 "P00   WARN: path '11-2/0000000200000007' does not contain any valid WAL to be processed\n"
                 "P00   INFO: Results:\n"
                 "              archiveId: 11-2, total WAL checked: 2, total valid WAL: 0\n"
-                "                missing: 0, checksum invalid: 0, size invalid: 0, other: 0")));
+                "                missing: 0, checksum invalid: 0, size invalid: 0, other: 0\n"
+                "              backup: none found")));
 
         harnessLogLevelReset();
 
@@ -797,14 +1057,16 @@ testRun(void)
         unsigned int errorTotal = 0;
         TEST_RESULT_STR_Z(
             verifyProcess(&errorTotal),
-            "Results:\n"
-            "  archiveId: 9.4-1, total WAL checked: 0, total valid WAL: 0\n"
-            "  archiveId: 11-2, total WAL checked: 4, total valid WAL: 2\n"
-            "    missing: 0, checksum invalid: 1, size invalid: 1, other: 0",
+            strZ(strNew(
+                "Results:\n"
+                "  archiveId: 9.4-1, total WAL checked: 0, total valid WAL: 0\n"
+                "  archiveId: 11-2, total WAL checked: 4, total valid WAL: 2\n"
+                "    missing: 0, checksum invalid: 1, size invalid: 1, other: 0\n"
+                "  backup: none found")),
             "verifyProcess() results");
         TEST_RESULT_UINT(errorTotal, 2, "errors");
         harnessLogResult(
-            strZ(strNewFmt(
+            strZ(strNew(
                 "P00   WARN: no backups exist in the repo\n"
                 "P00   WARN: archive path '9.4-1' is empty\n"
                 "P00   WARN: path '11-2/0000000100000000' does not contain any valid WAL to be processed\n"
@@ -848,14 +1110,14 @@ testRun(void)
 
         TEST_ERROR(cmdVerify(), RuntimeError, "2 fatal errors encountered, see log for details");
         harnessLogResult(
-            strZ(strNewFmt(
+            strZ(strNew(
                 "P01  ERROR: [028]: invalid checksum "
                     "'11-2/0000000200000007/000000020000000700000FFD-a6e1a64f0813352bc2e97f116a1800377e17d2e4.gz'\n"
                 "P01  ERROR: [028]: invalid size "
                     "'11-2/0000000200000007/000000020000000700000FFF-ee161f898c9012dd0c28b3fd1e7140b9cf411306'")));
 
         //--------------------------------------------------------------------------------------------------------------------------
-        TEST_TITLE("valid info files, unreadable WAL file");
+        TEST_TITLE("valid info files - various archive/backup errors");
 
         // Load Parameters - single non-default repo
         argList = strLstNew();
@@ -874,41 +1136,440 @@ testRun(void)
                 walBuffer),
             "write WAL - file not readable");
 
+        String *backupLabelPriorNoManifest = strNew("20181119-152800F");
+        TEST_RESULT_VOID(
+            storagePathCreateP(storageTest, strNewFmt("%s/%s", strZ(backupStanzaPath), strZ(backupLabelPriorNoManifest))),
+            "prior backup path missing manifests");
+
+        String *backupLabelManifestNoTargetFile = strNew("20181119-152810F");
+        const Buffer *contentLoad = harnessInfoChecksumZ
+        (
+            TEST_MANIFEST_HEADER
+            TEST_MANIFEST_DB_94
+            TEST_MANIFEST_OPTION_ALL
+            TEST_MANIFEST_TARGET
+            TEST_MANIFEST_DB
+        );
+
+        String *manifestFileNoTarget = strNewFmt(
+            "%s/%s/" BACKUP_MANIFEST_FILE, strZ(backupStanzaPath), strZ(backupLabelManifestNoTargetFile));
+        TEST_RESULT_VOID(
+            storagePutP(storageNewWriteP(storageTest, manifestFileNoTarget), contentLoad), "write manifest without target files");
+
+        // Create full backup with files
+        String *backupLabel = strNew("20181119-152900F");
+
+        TEST_RESULT_VOID(
+            storagePutP(storageNewWriteP(storageTest, strNewFmt("%s/%s/pg_data/PG_VERSION", strZ(backupStanzaPath),
+            strZ(backupLabel))), BUFSTRDEF("BOGUS")), "put checksum-error backup file");
+        TEST_RESULT_VOID(
+            storagePutP(storageNewWriteP(storageTest, strNewFmt("%s/%s/pg_data/testzero", strZ(backupStanzaPath),
+                strZ(backupLabel))), BUFSTRDEF("")), "put zero-size backup file");
+
+        TEST_RESULT_VOID(
+            storagePutP(storageNewWriteP(storageTest, strNewFmt("%s/%s/pg_data/testvalid", strZ(backupStanzaPath),
+            strZ(backupLabel))), BUFSTRZ(fileContents)), "put valid file");
+
+        contentLoad = harnessInfoChecksumZ
+        (
+            strZ(strNewFmt(
+                "[backup]\n"
+                "backup-label=\"%s\"\n"
+                "backup-timestamp-copy-start=0\n"
+                "backup-timestamp-start=0\n"
+                "backup-timestamp-stop=0\n"
+                "backup-type=\"full\"\n"
+                "\n"
+                "[backup:db]\n"
+                TEST_BACKUP_DB2_11
+                TEST_MANIFEST_OPTION_ALL
+                TEST_MANIFEST_TARGET
+                TEST_MANIFEST_DB
+                TEST_MANIFEST_FILE
+                "pg_data/testvalid={\"checksum\":\"%s\",\"master\":true,\"size\":7,\"timestamp\":1565282114}\n"
+                "pg_data/testzero={\"repo-size\":20,\"size\":0,\"timestamp\":1601405663}\n"
+                TEST_MANIFEST_FILE_DEFAULT
+                TEST_MANIFEST_LINK
+                TEST_MANIFEST_LINK_DEFAULT
+                TEST_MANIFEST_PATH
+                TEST_MANIFEST_PATH_DEFAULT,
+            strZ(backupLabel), strZ(fileChecksum)))
+        );
+
+        // Write manifests for full backup
+        String *manifestFile = strNewFmt("%s/%s/" BACKUP_MANIFEST_FILE, strZ(backupStanzaPath), strZ(backupLabel));
+        String *manifestFileCopy = strNewFmt("%s" INFO_COPY_EXT, strZ(manifestFile));
+        TEST_RESULT_VOID(
+            storagePutP(storageNewWriteP(storageTest, manifestFile), contentLoad), "write valid manifest");
+        TEST_RESULT_VOID(
+            storagePutP(storageNewWriteP(storageTest, manifestFileCopy), contentLoad),
+            "write valid manifest copy");
+
+        // Create a manifest for the dependent that has references
+        String *backupLabelDependent = strNew("20181119-152900F_20181119-152909D");
+
+        // Create an unprocessed backup label with a file that will be referenced in this manifest
+        String *unprocessedBackup = strNew("UNPROCESSEDBACKUP");
+        TEST_RESULT_VOID(
+            storagePutP(storageNewWriteP(storageTest, strNewFmt("%s/%s/pg_data/testother", strZ(backupStanzaPath),
+            strZ(unprocessedBackup)), .modeFile = 0200), BUFSTRZ(fileContents)), "put unreadable file to unprocessed backup");
+
+        contentLoad = harnessInfoChecksumZ
+        (
+            strZ(strNewFmt(
+                "[backup]\n"
+                "backup-label=\"%s\"\n"
+                "backup-timestamp-copy-start=0\n"
+                "backup-timestamp-start=0\n"
+                "backup-timestamp-stop=0\n"
+                "backup-type=\"diff\"\n"
+                "\n"
+                "[backup:db]\n"
+                TEST_BACKUP_DB2_11
+                TEST_MANIFEST_OPTION_ALL
+                TEST_MANIFEST_TARGET
+                TEST_MANIFEST_DB
+                "\n"
+                "[target:file]\n"
+                "pg_data/PG_VERSION="
+                    "{\"checksum\":\"184473f470864e067ee3a22e64b47b0a1c356f29\",\"master\":true,\"reference\":\"%s\",\"size\":4,"
+                    "\"timestamp\":1565282114}\n"
+                "pg_data/testfile={\"checksum\":\"%s\",\"master\":true,\"reference\":\"%s\",\"size\":7,\"timestamp\":1565282114}\n"
+                "pg_data/testfile2={\"checksum\":\"%s\",\"master\":true,\"size\":7,\"timestamp\":1565282114}\n"
+                "pg_data/testmissing="
+                    "{\"checksum\":\"123473f470864e067ee3a22e64b47b0a1c356abc\",\"size\":7,\"timestamp\":1565282114}\n"
+                "pg_data/testother={\"checksum\":\"%s\",\"master\":true,\"reference\":\"%s\",\"size\":7,\"timestamp\":1565282114}\n"
+                TEST_MANIFEST_FILE_DEFAULT
+                TEST_MANIFEST_LINK
+                TEST_MANIFEST_LINK_DEFAULT
+                TEST_MANIFEST_PATH
+                TEST_MANIFEST_PATH_DEFAULT,
+            strZ(backupLabelDependent), strZ(backupLabel), strZ(fileChecksum), strZ(backupLabel), strZ(fileChecksum),
+            strZ(fileChecksum), strZ(unprocessedBackup)))
+        );
+
+        // Write manifests for dependent backup
+        manifestFile = strNewFmt("%s/%s/" BACKUP_MANIFEST_FILE, strZ(backupStanzaPath), strZ(backupLabelDependent));
+        manifestFileCopy = strNewFmt("%s" INFO_COPY_EXT, strZ(manifestFile));
+
+        TEST_RESULT_VOID(
+            storagePutP(storageNewWriteP(storageTest, manifestFile), contentLoad), "write manifest to dependent");
+        TEST_RESULT_VOID(
+            storagePutP(storageNewWriteP(storageTest, manifestFileCopy), contentLoad), "write manifest copy to dependent");
+        TEST_RESULT_VOID(
+            storagePutP(storageNewWriteP(storageTest, strNewFmt("%s/%s/pg_data/testfile2", strZ(backupStanzaPath),
+            strZ(backupLabelDependent))), BUFSTRZ(fileContents)), "put valid file to dependent");
+
+        // Create in-progress backup
+        TEST_RESULT_VOID(
+            storagePathCreateP(storageTest, strNewFmt("%s/%s", strZ(backupStanzaPath), "20181119-153000F")),
+            "create empty backup path for newest backup so in-progress");
+
         // Set log level to capture ranges
         harnessLogLevelSet(logLevelDetail);
 
-        TEST_ERROR(cmdVerify(), RuntimeError, "3 fatal errors encountered, see log for details");
+        TEST_ERROR(cmdVerify(), RuntimeError, "7 fatal errors encountered, see log for details");
         harnessLogResult(
             strZ(strNewFmt(
-                "P00   WARN: no backups exist in the repo\n"
                 "P00   WARN: archive path '9.4-1' is empty\n"
                 "P00   WARN: path '11-2/0000000100000000' does not contain any valid WAL to be processed\n"
                 "P01  ERROR: [028]: invalid checksum "
                     "'11-2/0000000200000007/000000020000000700000FFD-a6e1a64f0813352bc2e97f116a1800377e17d2e4.gz'\n"
                 "P01  ERROR: [028]: invalid size "
                     "'11-2/0000000200000007/000000020000000700000FFF-ee161f898c9012dd0c28b3fd1e7140b9cf411306'\n"
-                "P01  ERROR: [039]: invalid verify "
+                "P01  ERROR: [039]: invalid result "
                     "11-2/0000000200000008/000000020000000800000003-656817043007aa2100c44c712bcb456db705dab9: [41] raised from "
                     "local-1 protocol: unable to open file "
                     "'%s/%s/11-2/0000000200000008/000000020000000800000003-656817043007aa2100c44c712bcb456db705dab9' for read: "
                     "[13] Permission denied\n"
+                "P00   WARN: unable to open missing file '%s/%s/20181119-152800F/backup.manifest' for read\n"
+                "P00   WARN: unable to open missing file '%s/%s/20181119-152800F/backup.manifest.copy' for read\n"
+                "P00   WARN: manifest missing for '20181119-152800F' - backup may have expired\n"
+                "P00   WARN: unable to open missing file '%s/%s/20181119-152810F/backup.manifest.copy' for read\n"
+                "P00  ERROR: [028]: backup '20181119-152810F' manifest does not contain any target files to verify\n"
+                "P01  ERROR: [028]: invalid checksum '20181119-152900F/pg_data/PG_VERSION'\n"
+                "P01  ERROR: [028]: file missing '20181119-152900F_20181119-152909D/pg_data/testmissing'\n"
+                "P00   WARN: unable to open missing file '%s/%s/20181119-153000F/backup.manifest' for read\n"
+                "P00   INFO: backup '20181119-153000F' appears to be in progress, skipping\n"
+                "P01  ERROR: [039]: invalid result UNPROCESSEDBACKUP/pg_data/testother: [41] raised from local-1 protocol: unable "
+                    "to open file '%s/%s/UNPROCESSEDBACKUP/pg_data/testother' for read: [13] Permission denied\n"
                 "P00 DETAIL: archiveId: 11-2, wal start: 000000020000000700000FFD, wal stop: 000000020000000800000000\n"
                 "P00 DETAIL: archiveId: 11-2, wal start: 000000020000000800000002, wal stop: 000000020000000800000003\n"
                 "P00 DETAIL: archiveId: 11-2, wal start: 000000030000000000000000, wal stop: 000000030000000000000001\n"
                 "P00   INFO: Results:\n"
                 "              archiveId: 9.4-1, total WAL checked: 0, total valid WAL: 0\n"
                 "              archiveId: 11-2, total WAL checked: 8, total valid WAL: 5\n"
-                "                missing: 0, checksum invalid: 1, size invalid: 1, other: 1",
-                 testPath(), strZ(archiveStanzaPath))));
+                "                missing: 0, checksum invalid: 1, size invalid: 1, other: 1\n"
+                "              backup: 20181119-152800F, status: manifest missing, total files checked: 0, total valid files: 0\n"
+                "              backup: 20181119-152810F, status: invalid, total files checked: 0, total valid files: 0\n"
+                "              backup: 20181119-152900F, status: invalid, total files checked: 3, total valid files: 2\n"
+                "                missing: 0, checksum invalid: 1, size invalid: 0, other: 0\n"
+                "              backup: 20181119-152900F_20181119-152909D, status: invalid, total files checked: 5, "
+                                                                                                            "total valid files: 2\n"
+                "                missing: 1, checksum invalid: 1, size invalid: 0, other: 1\n"
+                "              backup: 20181119-153000F, status: in-progress, total files checked: 0, total valid files: 0",
+                testPath(), strZ(archiveStanzaPath), testPath(), strZ(backupStanzaPath), testPath(), strZ(backupStanzaPath),
+                testPath(), strZ(backupStanzaPath), testPath(), strZ(backupStanzaPath), testPath(), strZ(backupStanzaPath))));
 
         harnessLogLevelReset();
+    }
+
+    // *****************************************************************************************************************************
+    if (testBegin("cmdVerify()"))
+    {
+        // Load Parameters
+        StringList *argList = strLstDup(argListBase);
+        harnessCfgLoad(cfgCmdVerify, argList);
+
+        // Backup labels
+        String *backupLabelFull = strNew("20181119-152900F");
+        String *backupLabelDiff = strNew("20181119-152900F_20181119-152909D");
+        String *backupLabelFullDb2 = strNew("20201119-163000F");
+
+        #define TEST_BACKUP_DB1_CURRENT_FULL3_DIFF1                                                                                \
+            "20181119-152900F_20181119-152909D={"                                                                                  \
+            "\"backrest-format\":5,\"backrest-version\":\"2.08dev\","                                                              \
+            "\"backup-archive-start\":\"000000010000000000000006\",\"backup-archive-stop\":\"000000010000000000000007\","          \
+            "\"backup-info-repo-size\":2369186,\"backup-info-repo-size-delta\":2369186,"                                           \
+            "\"backup-info-size\":20162900,\"backup-info-size-delta\":20162900,"                                                   \
+            "\"backup-timestamp-start\":1542640898,\"backup-timestamp-stop\":1542640911,\"backup-type\":\"full\","                 \
+            "\"db-id\":1,\"option-archive-check\":true,\"option-archive-copy\":false,\"option-backup-standby\":false,"             \
+            "\"option-checksum-page\":true,\"option-compress\":true,\"option-hardlink\":false,\"option-online\":true}\n"
+
+        #define TEST_BACKUP_DB2_CURRENT_FULL1                                                                                      \
+            "20201119-163000F={"                                                                                                   \
+            "\"backrest-format\":5,\"backrest-version\":\"2.08dev\","                                                              \
+            "\"backup-archive-start\":\"000000020000000000000001\",\"backup-archive-stop\":\"000000020000000000000001\","          \
+            "\"backup-info-repo-size\":2369186,\"backup-info-repo-size-delta\":2369186,"                                           \
+            "\"backup-info-size\":20162900,\"backup-info-size-delta\":20162900,"                                                   \
+            "\"backup-timestamp-start\":1542640898,\"backup-timestamp-stop\":1542640911,\"backup-type\":\"full\","                 \
+            "\"db-id\":2,\"option-archive-check\":true,\"option-archive-copy\":false,\"option-backup-standby\":false,"             \
+            "\"option-checksum-page\":true,\"option-compress\":true,\"option-hardlink\":false,\"option-online\":true}\n"
+
+        //--------------------------------------------------------------------------------------------------------------------------
+        TEST_TITLE("prior backup verification incomplete - referenced file checked");
 
         TEST_RESULT_VOID(
-            storageRemoveP(
-                storageTest,
-                strNewFmt("%s/11-2/0000000200000008/000000020000000800000003-656817043007aa2100c44c712bcb456db705dab9",
-                    strZ(archiveStanzaPath))),
-            "remove unreadable WAL");
+            storagePutP(storageNewWriteP(storageTest, archiveInfoFileName), archiveInfoMultiHistoryBase),
+            "write archive.info");
+        storageCopy(storageNewReadP(storageTest, archiveInfoFileName), storageNewWriteP(storageTest, archiveInfoFileNameCopy));
+
+        TEST_RESULT_VOID(
+            storagePutP(storageNewWriteP(storageTest, backupInfoFileName),
+                harnessInfoChecksumZ(
+                    "[backup:current]\n"
+                    TEST_BACKUP_DB1_CURRENT_FULL3
+                    TEST_BACKUP_DB1_CURRENT_FULL3_DIFF1
+                    TEST_BACKUP_DB2_CURRENT_FULL1
+                    "\n"
+                    "[db]\n"
+                    TEST_BACKUP_DB2_11
+                    "\n"
+                    "[db:history]\n"
+                    TEST_BACKUP_DB1_HISTORY
+                    "\n"
+                    TEST_BACKUP_DB2_HISTORY
+                    )),
+            "write backup.info");
+        storageCopy(storageNewReadP(storageTest, backupInfoFileName), storageNewWriteP(storageTest, backupInfoFileNameCopy));
+
+        // Create valid full backup and valid diff backup for DB1
+        const Buffer *contentLoad = harnessInfoChecksumZ
+        (
+            TEST_MANIFEST_HEADER
+            TEST_MANIFEST_DB_94
+            TEST_MANIFEST_OPTION_ALL
+            TEST_MANIFEST_TARGET
+            TEST_MANIFEST_DB
+            TEST_MANIFEST_FILE
+            TEST_MANIFEST_FILE_DEFAULT
+            TEST_MANIFEST_LINK
+            TEST_MANIFEST_LINK_DEFAULT
+            TEST_MANIFEST_PATH
+            TEST_MANIFEST_PATH_DEFAULT
+        );
+
+        // Write manifests for full backup
+        String *manifestFile = strNewFmt("%s/%s/" BACKUP_MANIFEST_FILE, strZ(backupStanzaPath), strZ(backupLabelFull));
+        String *manifestFileCopy = strNewFmt("%s" INFO_COPY_EXT, strZ(manifestFile));
+        TEST_RESULT_VOID(
+            storagePutP(storageNewWriteP(storageTest, manifestFile), contentLoad), "write valid manifest - full");
+        TEST_RESULT_VOID(
+            storagePutP(storageNewWriteP(storageTest, manifestFileCopy), contentLoad), "write valid manifest copy - full");
+
+        contentLoad = harnessInfoChecksumZ
+        (
+            strZ(strNewFmt(
+                TEST_MANIFEST_HEADER
+                TEST_MANIFEST_DB_94
+                TEST_MANIFEST_OPTION_ALL
+                TEST_MANIFEST_TARGET
+                TEST_MANIFEST_DB
+                "\n"
+                "[target:file]\n"
+                "pg_data/PG_VERSION="
+                    "{\"checksum\":\"184473f470864e067ee3a22e64b47b0a1c356f29\",\"master\":true,\"reference\":\"%s\",\"size\":4,"
+                    "\"timestamp\":1565282114}\n"
+                TEST_MANIFEST_FILE_DEFAULT
+                TEST_MANIFEST_LINK
+                TEST_MANIFEST_LINK_DEFAULT
+                TEST_MANIFEST_PATH
+                TEST_MANIFEST_PATH_DEFAULT,
+            strZ(backupLabelFull)))
+        );
+
+        // Write manifests for diff backup
+        String *manifestFileDiff = strNewFmt("%s/%s/" BACKUP_MANIFEST_FILE, strZ(backupStanzaPath), strZ(backupLabelDiff));
+        String *manifestFileCopyDiff = strNewFmt("%s" INFO_COPY_EXT, strZ(manifestFileDiff));
+        TEST_RESULT_VOID(
+            storagePutP(storageNewWriteP(storageTest, manifestFileDiff), contentLoad), "write valid manifest - diff");
+        TEST_RESULT_VOID(
+            storagePutP(storageNewWriteP(storageTest, manifestFileCopyDiff), contentLoad), "write valid manifest copy - diff");
+
+        // Put the file referenced by both backups into the full backup
+        String *filePathName = strNewFmt(STORAGE_REPO_BACKUP "/%s/pg_data/PG_VERSION", strZ(backupLabelFull));
+        TEST_RESULT_VOID(storagePutP(storageNewWriteP(storageRepoWrite(), filePathName), BUFSTRZ(fileContents)), "put file");
+
+        TEST_ERROR(cmdVerify(), RuntimeError, "2 fatal errors encountered, see log for details");
+
+        // The error for the referenced file is logged twice because it is checked again by the second backup since the first backup
+        // verification had not yet completed before the second backup verification began
+        harnessLogResult(
+            strZ(strNewFmt(
+                "P00   WARN: no archives exist in the repo\n"
+                "P01  ERROR: [028]: invalid checksum '%s/pg_data/PG_VERSION'\n"
+                "P01  ERROR: [028]: invalid checksum '%s/pg_data/PG_VERSION'\n"
+                "P00   INFO: Results:\n"
+                "              archiveId: none found\n"
+                "              backup: %s, status: invalid, total files checked: 1, total valid files: 0\n"
+                "                missing: 0, checksum invalid: 1, size invalid: 0, other: 0\n"
+                "              backup: %s, status: invalid, total files checked: 1, total valid files: 0\n"
+                "                missing: 0, checksum invalid: 1, size invalid: 0, other: 0",
+                strZ(backupLabelFull), strZ(backupLabelFull), strZ(backupLabelFull), strZ(backupLabelDiff))));
+
+        //--------------------------------------------------------------------------------------------------------------------------
+        TEST_TITLE("valid backup, prior backup verification complete - referenced file not checked");
+
+        // Set process max to 1 and add more files to check so first backup completes before second is checked
+        strLstAddZ(argList, "--process-max=1");
+        harnessCfgLoad(cfgCmdVerify, argList);
+
+        contentLoad = harnessInfoChecksumZ
+        (
+            strZ(strNewFmt(
+                TEST_MANIFEST_HEADER
+                TEST_MANIFEST_DB_94
+                TEST_MANIFEST_OPTION_ALL
+                TEST_MANIFEST_TARGET
+                TEST_MANIFEST_DB
+                TEST_MANIFEST_FILE
+                "pg_data/base/1/555_init="
+                    "{\"checksum\":\"%s\",\"master\":false,\"size\":1,\"timestamp\":1565282114}\n"
+                "pg_data/base/1/555_init.1={\"master\":false,\"size\":0,\"timestamp\":1565282114}\n"
+                TEST_MANIFEST_FILE_DEFAULT
+                TEST_MANIFEST_LINK
+                TEST_MANIFEST_LINK_DEFAULT
+                TEST_MANIFEST_PATH
+                TEST_MANIFEST_PATH_DEFAULT,
+                strZ(fileChecksum)))
+        );
+        TEST_RESULT_VOID(
+            storagePutP(storageNewWriteP(storageTest, manifestFile), contentLoad), "write valid manifest - full");
+        TEST_RESULT_VOID(
+            storagePutP(storageNewWriteP(storageTest, manifestFileCopy), contentLoad), "write valid manifest copy - full");
+        filePathName = strNewFmt(STORAGE_REPO_BACKUP "/%s/pg_data/base/1/555_init", strZ(backupLabelFull));
+        TEST_RESULT_VOID(storagePutP(storageNewWriteP(storageRepoWrite(), filePathName), BUFSTRZ(fileContents)),
+            "put file - invalid size");
+
+        contentLoad = harnessInfoChecksumZ
+        (
+            strZ(strNewFmt(
+                TEST_MANIFEST_HEADER
+                TEST_MANIFEST_DB_94
+                TEST_MANIFEST_OPTION_ALL
+                TEST_MANIFEST_TARGET
+                TEST_MANIFEST_DB
+                "\n"
+                "[target:file]\n"
+                "pg_data/PG_VERSION="
+                    "{\"checksum\":\"184473f470864e067ee3a22e64b47b0a1c356f29\",\"master\":true,\"reference\":\"%s\",\"size\":4,"
+                    "\"timestamp\":1565282114}\n"
+                TEST_MANIFEST_FILE_DEFAULT
+                TEST_MANIFEST_LINK
+                TEST_MANIFEST_LINK_DEFAULT
+                TEST_MANIFEST_PATH
+                TEST_MANIFEST_PATH_DEFAULT,
+                strZ(backupLabelFull)))
+        );
+        TEST_RESULT_VOID(
+            storagePutP(storageNewWriteP(storageTest, manifestFileDiff), contentLoad), "write valid manifest - diff");
+        TEST_RESULT_VOID(
+            storagePutP(storageNewWriteP(storageTest, manifestFileCopyDiff), contentLoad), "write valid manifest copy - diff");
+
+        // Create valid full backup and valid diff backup
+        contentLoad = harnessInfoChecksumZ
+        (
+            strZ(strNewFmt(
+                TEST_MANIFEST_HEADER
+                "\n"
+                "[backup:db]\n"
+                TEST_BACKUP_DB2_11
+                TEST_MANIFEST_OPTION_ALL
+                TEST_MANIFEST_TARGET
+                TEST_MANIFEST_DB
+                "\n"
+                "[target:file]\n"
+                "pg_data/validfile={\"checksum\":\"%s\",\"master\":true,\"size\":%u,\"timestamp\":1565282114}\n"
+                TEST_MANIFEST_FILE_DEFAULT
+                TEST_MANIFEST_LINK
+                TEST_MANIFEST_LINK_DEFAULT
+                TEST_MANIFEST_PATH
+                TEST_MANIFEST_PATH_DEFAULT,
+                strZ(fileChecksum), (unsigned int)fileSize))
+        );
+
+        manifestFile = strNewFmt("%s/%s/" BACKUP_MANIFEST_FILE, strZ(backupStanzaPath), strZ(backupLabelFullDb2));
+        manifestFileCopy = strNewFmt("%s" INFO_COPY_EXT, strZ(manifestFile));
+        TEST_RESULT_VOID(
+            storagePutP(storageNewWriteP(storageTest, manifestFile), contentLoad), "write valid manifest - full");
+        TEST_RESULT_VOID(
+            storagePutP(storageNewWriteP(storageTest, manifestFileCopy), contentLoad), "write valid manifest copy - full");
+        filePathName =  strNewFmt(STORAGE_REPO_BACKUP "/%s/pg_data/validfile", strZ(backupLabelFullDb2));
+        TEST_RESULT_VOID(storagePutP(storageNewWriteP(storageRepoWrite(), filePathName), BUFSTRZ(fileContents)), "put valid file");
+
+        // Create WAL file with just header info and small WAL size
+        Buffer *walBuffer = bufNew((size_t)(1024 * 1024));
+        bufUsedSet(walBuffer, bufSize(walBuffer));
+        memset(bufPtr(walBuffer), 0, bufSize(walBuffer));
+        pgWalTestToBuffer(
+            (PgWal){.version = PG_VERSION_11, .systemId = 6626363367545678089, .size = 1024 * 1024}, walBuffer);
+        const char *walBufferSha1 = strZ(bufHex(cryptoHashOne(HASH_TYPE_SHA1_STR, walBuffer)));
+        TEST_RESULT_VOID(
+            storagePutP(
+                storageNewWriteP(
+                    storageTest,
+                    strNewFmt("%s/11-2/0000000200000000/000000020000000000000001-%s", strZ(archiveStanzaPath), walBufferSha1)),
+                walBuffer),
+            "write valid WAL");
+
+        TEST_ERROR(cmdVerify(), RuntimeError, "3 fatal errors encountered, see log for details");
+
+        harnessLogResult(
+            strZ(strNewFmt(
+                "P01  ERROR: [028]: invalid checksum '%s/pg_data/PG_VERSION'\n"
+                "P01  ERROR: [028]: invalid size '%s/pg_data/base/1/555_init'\n"
+                "P01  ERROR: [028]: file missing '%s/pg_data/base/1/555_init.1'\n"
+                "P00   INFO: Results:\n"
+                "              archiveId: 11-2, total WAL checked: 1, total valid WAL: 1\n"
+                "                missing: 0, checksum invalid: 0, size invalid: 0, other: 0\n"
+                "              backup: %s, status: invalid, total files checked: 3, total valid files: 0\n"
+                "                missing: 1, checksum invalid: 1, size invalid: 1, other: 0\n"
+                "              backup: %s, status: invalid, total files checked: 1, total valid files: 0\n"
+                "                missing: 0, checksum invalid: 1, size invalid: 0, other: 0\n"
+                "              backup: %s, status: valid, total files checked: 1, total valid files: 1\n"
+                "                missing: 0, checksum invalid: 0, size invalid: 0, other: 0",
+                strZ(backupLabelFull), strZ(backupLabelFull), strZ(backupLabelFull), strZ(backupLabelFull),
+                strZ(backupLabelDiff), strZ(backupLabelFullDb2))));
     }
 
     FUNCTION_HARNESS_RESULT_VOID();