diff --git a/src/citra_qt/main.cpp b/src/citra_qt/main.cpp
index d0292448d..c9b2e7ddf 100644
--- a/src/citra_qt/main.cpp
+++ b/src/citra_qt/main.cpp
@@ -96,8 +96,9 @@ void GMainWindow::ShowCallouts() {
 }
 
 GMainWindow::GMainWindow() : config(new Config()), emu_thread(nullptr) {
-    // register size_t to use in slots and signals
+    // register types to use in slots and signals
     qRegisterMetaType<size_t>("size_t");
+    qRegisterMetaType<Service::AM::InstallStatus>("Service::AM::InstallStatus");
 
     LoadTranslation();
 
@@ -382,6 +383,8 @@ void GMainWindow::ConnectWidgetEvents() {
     connect(&status_bar_update_timer, &QTimer::timeout, this, &GMainWindow::UpdateStatusBar);
 
     connect(this, &GMainWindow::UpdateProgress, this, &GMainWindow::OnUpdateProgress);
+    connect(this, &GMainWindow::CIAInstallReport, this, &GMainWindow::OnCIAInstallReport);
+    connect(this, &GMainWindow::CIAInstallFinished, this, &GMainWindow::OnCIAInstallFinished);
 }
 
 void GMainWindow::ConnectMenuEvents() {
@@ -791,24 +794,29 @@ void GMainWindow::OnMenuSelectGameListRoot() {
 }
 
 void GMainWindow::OnMenuInstallCIA() {
-    QString filepath = QFileDialog::getOpenFileName(
-        this, tr("Load File"), UISettings::values.roms_path,
+    QStringList filepaths = QFileDialog::getOpenFileNames(
+        this, tr("Load Files"), UISettings::values.roms_path,
         tr("3DS Installation File (*.CIA*)") + ";;" + tr("All Files (*.*)"));
-    if (filepath.isEmpty())
+    if (filepaths.isEmpty())
         return;
 
     ui.action_Install_CIA->setEnabled(false);
     progress_bar->show();
-    watcher = new QFutureWatcher<Service::AM::InstallStatus>;
-    QFuture<Service::AM::InstallStatus> f = QtConcurrent::run([&, filepath] {
-        const auto cia_progress = [&](size_t written, size_t total) {
-            emit UpdateProgress(written, total);
-        };
-        return Service::AM::InstallCIA(filepath.toStdString(), cia_progress);
+
+    QtConcurrent::run([&, filepaths] {
+        QString current_path;
+        Service::AM::InstallStatus status;
+        for (int current_index = 0; current_index < filepaths.size(); current_index++) {
+            const auto cia_progress = [&](size_t written, size_t total) {
+                emit UpdateProgress(written, total);
+            };
+            current_path = filepaths.at(current_index);
+            status = Service::AM::InstallCIA(current_path.toStdString(), cia_progress);
+            emit CIAInstallReport(status, current_path);
+        }
+        emit CIAInstallFinished();
+        return;
     });
-    connect(watcher, &QFutureWatcher<Service::AM::InstallStatus>::finished, this,
-            &GMainWindow::OnCIAInstallFinished);
-    watcher->setFuture(f);
 }
 
 void GMainWindow::OnUpdateProgress(size_t written, size_t total) {
@@ -816,32 +824,37 @@ void GMainWindow::OnUpdateProgress(size_t written, size_t total) {
     progress_bar->setValue(written);
 }
 
-void GMainWindow::OnCIAInstallFinished() {
-    progress_bar->hide();
-    progress_bar->setValue(0);
-    switch (watcher->future()) {
+void GMainWindow::OnCIAInstallReport(Service::AM::InstallStatus status, QString filepath) {
+    QString filename = QFileInfo(filepath).fileName();
+    switch (status) {
     case Service::AM::InstallStatus::Success:
-        this->statusBar()->showMessage(tr("The file has been installed successfully."));
+        this->statusBar()->showMessage(tr("%1 has been installed successfully.").arg(filename));
         break;
     case Service::AM::InstallStatus::ErrorFailedToOpenFile:
         QMessageBox::critical(this, tr("Unable to open File"),
-                              tr("Could not open the selected file"));
+                              tr("Could not open %1").arg(filename));
         break;
     case Service::AM::InstallStatus::ErrorAborted:
         QMessageBox::critical(
             this, tr("Installation aborted"),
-            tr("The installation was aborted. Please see the log for more details"));
+            tr("The installation of %1 was aborted. Please see the log for more details")
+                .arg(filename));
         break;
     case Service::AM::InstallStatus::ErrorInvalid:
-        QMessageBox::critical(this, tr("Invalid File"), tr("The selected file is not a valid CIA"));
+        QMessageBox::critical(this, tr("Invalid File"), tr("%1 is not a valid CIA").arg(filename));
         break;
     case Service::AM::InstallStatus::ErrorEncrypted:
         QMessageBox::critical(this, tr("Encrypted File"),
-                              tr("The file that you are trying to install must be decrypted "
-                                 "before being used with Citra. A real 3DS is required."));
+                              tr("%1 must be decrypted "
+                                 "before being used with Citra. A real 3DS is required.")
+                                  .arg(filename));
         break;
     }
-    delete watcher;
+}
+
+void GMainWindow::OnCIAInstallFinished() {
+    progress_bar->hide();
+    progress_bar->setValue(0);
     ui.action_Install_CIA->setEnabled(true);
 }
 
@@ -897,7 +910,8 @@ void GMainWindow::OnMenuReportCompatibility() {
         QMessageBox::critical(
             this, tr("Missing Citra Account"),
             tr("In order to submit a game compatibility test case, you must link your Citra "
-               "account.<br><br/>To link your Citra account, go to Emulation &gt; Configuration &gt; "
+               "account.<br><br/>To link your Citra account, go to Emulation &gt; Configuration "
+               "&gt; "
                "Web."));
     }
 }
@@ -1045,11 +1059,10 @@ void GMainWindow::UpdateStatusBar() {
 
     if (Settings::values.use_frame_limit) {
         emu_speed_label->setText(tr("Speed: %1% / %2%")
-                                    .arg(results.emulation_speed * 100.0, 0, 'f', 0)
-                                    .arg(Settings::values.frame_limit));
+                                     .arg(results.emulation_speed * 100.0, 0, 'f', 0)
+                                     .arg(Settings::values.frame_limit));
     } else {
-        emu_speed_label->setText(tr("Speed: %1%")
-                                    .arg(results.emulation_speed * 100.0, 0, 'f', 0));
+        emu_speed_label->setText(tr("Speed: %1%").arg(results.emulation_speed * 100.0, 0, 'f', 0));
     }
     game_fps_label->setText(tr("Game: %1 FPS").arg(results.game_fps, 0, 'f', 0));
     emu_frametime_label->setText(tr("Frame: %1 ms").arg(results.frametime * 1000.0, 0, 'f', 2));
diff --git a/src/citra_qt/main.h b/src/citra_qt/main.h
index 763ffab65..85fbc7d02 100644
--- a/src/citra_qt/main.h
+++ b/src/citra_qt/main.h
@@ -70,7 +70,10 @@ signals:
      * system emulation handles and memory are still valid, but are about become invalid.
      */
     void EmulationStopping();
+
     void UpdateProgress(size_t written, size_t total);
+    void CIAInstallReport(Service::AM::InstallStatus status, QString filepath);
+    void CIAInstallFinished();
 
 private:
     void InitializeWidgets();
@@ -136,6 +139,7 @@ private slots:
     void OnMenuLoadFile();
     void OnMenuInstallCIA();
     void OnUpdateProgress(size_t written, size_t total);
+    void OnCIAInstallReport(Service::AM::InstallStatus status, QString filepath);
     void OnCIAInstallFinished();
     /// Called whenever a user selects the "File->Select Game List Root" menu item
     void OnMenuSelectGameListRoot();
@@ -168,7 +172,6 @@ private:
 
     GRenderWindow* render_window;
     GameList* game_list;
-    QFutureWatcher<Service::AM::InstallStatus>* watcher = nullptr;
 
     // Status bar elements
     QProgressBar* progress_bar = nullptr;
@@ -210,3 +213,4 @@ protected:
 };
 
 Q_DECLARE_METATYPE(size_t);
+Q_DECLARE_METATYPE(Service::AM::InstallStatus);