diff --git a/python/gui/auto_generated/qgsrasterlayersaveasdialog.sip.in b/python/gui/auto_generated/qgsrasterlayersaveasdialog.sip.in
index 78d6ee5ef29..8c68677d3ea 100644
--- a/python/gui/auto_generated/qgsrasterlayersaveasdialog.sip.in
+++ b/python/gui/auto_generated/qgsrasterlayersaveasdialog.sip.in
@@ -54,6 +54,7 @@ Constructor for QgsRasterLayerSaveAsDialog
     bool tileMode() const;
     bool addToCanvas() const;
     QString outputFileName() const;
+    QString outputLayerName() const;
     QString outputFormat() const;
     QgsCoordinateReferenceSystem outputCrs();
     QStringList createOptions() const;
@@ -72,6 +73,7 @@ Constructor for QgsRasterLayerSaveAsDialog
   public slots:
     virtual void accept();
 
+
 };
 
 
diff --git a/src/app/qgisapp.cpp b/src/app/qgisapp.cpp
index cac5ffef8b0..d40269227ba 100644
--- a/src/app/qgisapp.cpp
+++ b/src/app/qgisapp.cpp
@@ -7156,13 +7156,16 @@ void QgisApp::saveAsRasterFile( QgsRasterLayer *rasterLayer )
   bool tileMode = d.tileMode();
   bool addToCanvas = d.addToCanvas();
   QPointer< QgsRasterLayer > rlWeakPointer( rasterLayer );
+  QString outputLayerName = d.outputLayerName();
+  QString outputFormat = d.outputFormat();
 
   QgsRasterFileWriterTask *writerTask = new QgsRasterFileWriterTask( fileWriter, pipe.release(), d.nColumns(), d.nRows(),
       d.outputRectangle(), d.outputCrs() );
 
   // when writer is successful:
 
-  connect( writerTask, &QgsRasterFileWriterTask::writeComplete, this, [this, tileMode, addToCanvas, rlWeakPointer ]( const QString & newFilename )
+  connect( writerTask, &QgsRasterFileWriterTask::writeComplete, this,
+           [this, tileMode, addToCanvas, rlWeakPointer, outputLayerName, outputFormat]( const QString & newFilename )
   {
     QString fileName = newFilename;
     if ( tileMode )
@@ -7173,7 +7176,14 @@ void QgisApp::saveAsRasterFile( QgsRasterLayer *rasterLayer )
 
     if ( addToCanvas )
     {
-      addRasterLayers( QStringList( fileName ) );
+      if ( outputFormat == QLatin1String( "GPKG" ) && !outputLayerName.isEmpty() )
+      {
+        addRasterLayers( QStringList( QStringLiteral( "GPKG:%1:%2" ).arg( fileName, outputLayerName ) ) );
+      }
+      else
+      {
+        addRasterLayers( QStringList( fileName ) );
+      }
     }
     if ( rlWeakPointer )
       emit layerSavedAs( rlWeakPointer, fileName );
@@ -12811,7 +12821,17 @@ bool QgisApp::addRasterLayers( QStringList const &fileNameQStringList, bool guiW
       QFileInfo myFileInfo( *myIterator );
 
       // try to create the layer
-      QgsRasterLayer *layer = addRasterLayerPrivate( *myIterator, myFileInfo.completeBaseName(),
+      // set the layer name to the file base name...
+      QString layerName = myFileInfo.completeBaseName();
+
+      // ...unless the layer uri matches "GPKG:filePath:layerName" and layerName differs from the file base name
+      QStringList layerUriSegments = myIterator->split( QLatin1String( ":" ) );
+      if ( layerUriSegments.count() == 3 && layerUriSegments[ 0 ] ==  QLatin1String( "GPKG" ) && layerUriSegments[ 2 ] != layerName )
+      {
+        layerName = QStringLiteral( "%1 %2" ).arg( layerName, layerUriSegments[ 2 ] );
+      }
+
+      QgsRasterLayer *layer = addRasterLayerPrivate( *myIterator, layerName,
                               QString(), guiWarning, true );
       if ( layer && layer->isValid() )
       {
diff --git a/src/gui/qgsrasterlayersaveasdialog.cpp b/src/gui/qgsrasterlayersaveasdialog.cpp
index 3f6110acf8d..4b4c621b376 100644
--- a/src/gui/qgsrasterlayersaveasdialog.cpp
+++ b/src/gui/qgsrasterlayersaveasdialog.cpp
@@ -179,6 +179,12 @@ QgsRasterLayerSaveAsDialog::QgsRasterLayerSaveAsDialog( QgsRasterLayer *rasterLa
     QFileInfo tmplFileInfo( filePath );
     settings.setValue( QStringLiteral( "UI/lastRasterFileDir" ), tmplFileInfo.absolutePath() );
 
+    if ( !filePath.isEmpty() && mLayerName->isEnabled() )
+    {
+      QFileInfo fileInfo( filePath );
+      mLayerName->setText( fileInfo.baseName() );
+    }
+
     if ( mTileModeCheckBox->isChecked() )
     {
       QString fileName = filePath;
@@ -314,6 +320,18 @@ void QgsRasterLayerSaveAsDialog::mFormatComboBox_currentIndexChanged( const QStr
              tr( "All files (*.*)" ) );
   }
   mFilename->setFilter( filter );
+
+  mFilename->setConfirmOverwrite( outputFormat() != QStringLiteral( "GPKG" ) );
+  mLayerName->setEnabled( outputFormat() == QStringLiteral( "GPKG" ) );
+  if ( mLayerName->isEnabled() )
+  {
+    QString layerName = QFileInfo( mFilename->filePath() ).baseName();
+    mLayerName->setText( layerName );
+  }
+  else
+  {
+    mLayerName->setText( QString() );
+  }
 }
 
 int QgsRasterLayerSaveAsDialog::nColumns() const
@@ -380,6 +398,19 @@ QString QgsRasterLayerSaveAsDialog::outputFileName() const
   return fileName;
 }
 
+QString QgsRasterLayerSaveAsDialog::outputLayerName() const
+{
+  if ( mLayerName->text().isEmpty() && outputFormat() == QStringLiteral( "GPKG" ) && !mTileModeCheckBox->isChecked() )
+  {
+    // Always return layer name for GeoPackages
+    return QFileInfo( mFilename->filePath() ).baseName();
+  }
+  else
+  {
+    return mLayerName->text();
+  }
+}
+
 QString QgsRasterLayerSaveAsDialog::outputFormat() const
 {
   return mFormatComboBox->currentData().toString();
@@ -387,7 +418,35 @@ QString QgsRasterLayerSaveAsDialog::outputFormat() const
 
 QStringList QgsRasterLayerSaveAsDialog::createOptions() const
 {
-  return mCreateOptionsGroupBox->isChecked() ? mCreateOptionsWidget->options() : QStringList();
+  QStringList options = mCreateOptionsGroupBox->isChecked() ? mCreateOptionsWidget->options() : QStringList();
+  if ( outputFormat() == QStringLiteral( "GPKG" ) )
+  {
+    // Overwrite the GPKG table options
+    int indx = options.indexOf( QRegExp( "^RASTER_TABLE=.*" ) );
+    if ( indx > -1 )
+    {
+      options.replace( indx, QStringLiteral( "RASTER_TABLE=%1" ).arg( outputLayerName() ) );
+    }
+    else
+    {
+      options.append( QStringLiteral( "RASTER_TABLE=%1" ).arg( outputLayerName() ) );
+    }
+
+    // Only enable the append mode if the layer doesn't exist yet. For existing layers a 'confirm overwrite' dialog will be shown.
+    if ( !outputLayerExistsInGpkg() )
+    {
+      indx = options.indexOf( QRegExp( "^APPEND_SUBDATASET=.*", Qt::CaseInsensitive ) );
+      if ( indx > -1 )
+      {
+        options.replace ( indx, QStringLiteral( "APPEND_SUBDATASET=YES" ) );
+      }
+      else
+      {
+        options.append( QStringLiteral( "APPEND_SUBDATASET=YES" ) );
+      }
+    }
+  }
+  return options;
 }
 
 QgsRectangle QgsRasterLayerSaveAsDialog::outputRectangle() const
@@ -845,6 +904,32 @@ bool QgsRasterLayerSaveAsDialog::validate() const
   return true;
 }
 
+bool QgsRasterLayerSaveAsDialog::outputLayerExistsInGpkg() const
+{
+  QgsRasterLayer *layer = nullptr;
+  layer = new QgsRasterLayer( QStringLiteral( "GPKG:%1:%2" ).arg( outputFileName(), outputLayerName() ), "", QStringLiteral( "gdal" ) );
+  return layer->isValid();
+}
+
+void QgsRasterLayerSaveAsDialog::accept()
+{
+  if ( !validate() )
+  {
+    return;
+  }
+
+  if ( outputFormat() == QStringLiteral( "GPKG" ) && outputLayerExistsInGpkg() &&
+       QMessageBox::warning( this, tr( "Save Raster Layer" ),
+                             tr( "The layer %1 already exists in the target file, and overwriting layers in GeoPackage is not supported. "
+                                 "Do you want to overwrite the whole file?" ).arg( outputLayerName() ),
+                             QMessageBox::Yes | QMessageBox::No ) == QMessageBox::No )
+  {
+    return;
+  }
+
+  QDialog::accept();
+}
+
 void QgsRasterLayerSaveAsDialog::showHelp()
 {
   QgsHelp::openHelp( QStringLiteral( "managing_data_source/create_layers.html#save-layer-from-an-existing-file" ) );
diff --git a/src/gui/qgsrasterlayersaveasdialog.h b/src/gui/qgsrasterlayersaveasdialog.h
index 5b24a0b3127..a828ab35e05 100644
--- a/src/gui/qgsrasterlayersaveasdialog.h
+++ b/src/gui/qgsrasterlayersaveasdialog.h
@@ -71,6 +71,7 @@ class GUI_EXPORT QgsRasterLayerSaveAsDialog: public QDialog, private Ui::QgsRast
     bool tileMode() const;
     bool addToCanvas() const;
     QString outputFileName() const;
+    QString outputLayerName() const;
     QString outputFormat() const;
     QgsCoordinateReferenceSystem outputCrs();
     QStringList createOptions() const;
@@ -87,7 +88,7 @@ class GUI_EXPORT QgsRasterLayerSaveAsDialog: public QDialog, private Ui::QgsRast
     void hideOutput();
 
   public slots:
-    void accept() override { if ( validate() ) QDialog::accept(); }
+    void accept() override;
 
   private slots:
     void mRawModeRadioButton_toggled( bool );
@@ -138,6 +139,7 @@ class GUI_EXPORT QgsRasterLayerSaveAsDialog: public QDialog, private Ui::QgsRast
     double noDataCellValue( int row, int column ) const;
     void adjustNoDataCellWidth( int row, int column );
     bool validate() const;
+    bool outputLayerExistsInGpkg() const;
 
     void insertAvailableOutputFormats();
 };
diff --git a/src/ui/qgsrasterlayersaveasdialogbase.ui b/src/ui/qgsrasterlayersaveasdialogbase.ui
index 2137d439dfc..e92a8bf327c 100644
--- a/src/ui/qgsrasterlayersaveasdialogbase.ui
+++ b/src/ui/qgsrasterlayersaveasdialogbase.ui
@@ -7,7 +7,7 @@
     0
     0
     575
-    580
+    610
    
   
   
@@ -86,7 +86,7 @@
        
       
      
-     - 
+     
- 
       
        
         Qt::StrongFocus
@@ -118,7 +118,7 @@ datasets with maximum width and height specified below.
        
 
       
       
-     - 
+     
- 
       
        
         
@@ -147,7 +147,7 @@ datasets with maximum width and height specified below.
        
       
      
 
-     - 
+     
- 
       
        
         Add saved file to map
@@ -157,6 +157,16 @@ datasets with maximum width and height specified below.
        
       
      
 
+     - 
+      
+       
+        Layer name
+       
+      
+     
 
+     - 
+      
+     
 
     
     
    - 
@@ -716,6 +726,7 @@ datasets with maximum width and height specified below.
   mFormatComboBox
   mTileModeCheckBox
   mFilename
+  mLayerName
   mCrsSelector
   mAddToCanvas
   mScrollArea