diff --git a/src/app/qgisapp.cpp b/src/app/qgisapp.cpp
index 49eacc8cbb7..8df81e03efe 100644
--- a/src/app/qgisapp.cpp
+++ b/src/app/qgisapp.cpp
@@ -744,6 +744,12 @@ QgisApp::QgisApp( QSplashScreen *splash, bool restorePlugins, bool skipVersionCh
 
   startProfile( QStringLiteral( "Welcome page" ) );
   mWelcomePage = new QgsWelcomePage( skipVersionCheck );
+  connect( mWelcomePage, &QgsWelcomePage::projectRemoved, this, [ this ]( int row )
+  {
+    mRecentProjects.removeAt( row );
+    saveRecentProjects();
+  } );
+
   endProfile();
 
   mCentralContainer = new QStackedWidget;
@@ -3830,8 +3836,6 @@ void QgisApp::saveRecentProjectPath( const QString &projectPath, bool savePrevie
   // projects when multiple QGIS sessions are open
   readRecentProjects();
 
-  QgsSettings settings;
-
   // Get canonical absolute path
   QFileInfo myFileInfo( projectPath );
   QgsWelcomePageItemsModel::RecentProjectData projectData;
@@ -3883,10 +3887,22 @@ void QgisApp::saveRecentProjectPath( const QString &projectPath, bool savePrevie
     QFile( mRecentProjects.takeLast().previewImagePath ).remove();
   }
 
+  // Persist the list
+  saveRecentProjects();
+
+  // Update menu list of paths
+  updateRecentProjectPaths();
+
+} // QgisApp::saveRecentProjectPath
+
+// Save recent projects list to settings
+void QgisApp::saveRecentProjects()
+{
+  QgsSettings settings;
+
   settings.remove( QStringLiteral( "/UI/recentProjects" ) );
   int idx = 0;
 
-  // Persist the list
   Q_FOREACH ( const QgsWelcomePageItemsModel::RecentProjectData &recentProject, mRecentProjects )
   {
     ++idx;
@@ -3897,11 +3913,7 @@ void QgisApp::saveRecentProjectPath( const QString &projectPath, bool savePrevie
     settings.setValue( QStringLiteral( "crs" ), recentProject.crs );
     settings.endGroup();
   }
-
-  // Update menu list of paths
-  updateRecentProjectPaths();
-
-} // QgisApp::saveRecentProjectPath
+}
 
 // Update project menu with the project templates
 void QgisApp::updateProjectFromTemplates()
diff --git a/src/app/qgisapp.h b/src/app/qgisapp.h
index ac1d0ba5f97..e6b7de41c29 100644
--- a/src/app/qgisapp.h
+++ b/src/app/qgisapp.h
@@ -1691,6 +1691,8 @@ class APP_EXPORT QgisApp : public QMainWindow, private Ui::MainWindow
      * \param savePreviewImage Set to false when the preview image should not be saved. E.g. project load.
      */
     void saveRecentProjectPath( const QString &projectPath, bool savePreviewImage = true );
+    //! Save recent projects list to settings
+    void saveRecentProjects();
     //! Update project menu with the current list of recently accessed projects
     void updateRecentProjectPaths();
     //! Read Well Known Binary stream from PostGIS
diff --git a/src/app/qgswelcomepage.cpp b/src/app/qgswelcomepage.cpp
index 8de005ab2c4..f51c1105de5 100644
--- a/src/app/qgswelcomepage.cpp
+++ b/src/app/qgswelcomepage.cpp
@@ -145,6 +145,13 @@ void QgsWelcomePage::showContextMenuForProjects( QPoint point )
     } );
     menu->addAction( rescanAction );
   }
+  QAction *removeProjectAction = new QAction( tr( "Remove from List" ), menu );
+  connect( removeProjectAction, &QAction::triggered, this, [this, index]
+  {
+    mModel->removeProject( index );
+    emit projectRemoved( index.row() );
+  } );
+  menu->addAction( removeProjectAction );
 
   menu->popup( mapToGlobal( point ) );
 }
diff --git a/src/app/qgswelcomepage.h b/src/app/qgswelcomepage.h
index 55c0825040b..3bcded42d86 100644
--- a/src/app/qgswelcomepage.h
+++ b/src/app/qgswelcomepage.h
@@ -35,6 +35,9 @@ class QgsWelcomePage : public QWidget
 
     void setRecentProjects( const QList<QgsWelcomePageItemsModel::RecentProjectData> &recentProjects );
 
+  signals:
+    void projectRemoved( int row );
+
   private slots:
     void itemActivated( const QModelIndex &index );
     void versionInfoReceived();
diff --git a/src/app/qgswelcomepageitemsmodel.cpp b/src/app/qgswelcomepageitemsmodel.cpp
index 0c909db912c..84a424983b7 100644
--- a/src/app/qgswelcomepageitemsmodel.cpp
+++ b/src/app/qgswelcomepageitemsmodel.cpp
@@ -214,6 +214,11 @@ Qt::ItemFlags QgsWelcomePageItemsModel::flags( const QModelIndex &index ) const
   return flags;
 }
 
+void QgsWelcomePageItemsModel::removeProject( const QModelIndex &index )
+{
+  mRecentProjects.removeAt( index.row() );
+}
+
 void QgsWelcomePageItemsModel::recheckProject( const QModelIndex &index )
 {
   const RecentProjectData &projectData = mRecentProjects.at( index.row() );
diff --git a/src/app/qgswelcomepageitemsmodel.h b/src/app/qgswelcomepageitemsmodel.h
index 1b20105a7ce..31dcb23c406 100644
--- a/src/app/qgswelcomepageitemsmodel.h
+++ b/src/app/qgswelcomepageitemsmodel.h
@@ -62,6 +62,7 @@ class QgsWelcomePageItemsModel : public QAbstractListModel
     QVariant data( const QModelIndex &index, int role ) const override;
     Qt::ItemFlags flags( const QModelIndex &index ) const override;
 
+    void removeProject( const QModelIndex &index );
     void recheckProject( const QModelIndex &index );
 
   private: