diff --git a/src/app/application.cpp b/src/app/application.cpp
index 88076b7f4..698a14a7b 100644
--- a/src/app/application.cpp
+++ b/src/app/application.cpp
@@ -504,53 +504,19 @@ int Application::exec(const QStringList &params)
     connect(BitTorrent::Session::instance(), &BitTorrent::Session::torrentFinished, this, &Application::torrentFinished);
     connect(BitTorrent::Session::instance(), &BitTorrent::Session::allTorrentsFinished, this, &Application::allTorrentsFinished, Qt::QueuedConnection);
 
-#ifndef DISABLE_COUNTRIES_RESOLUTION
-    Net::GeoIPManager::initInstance();
-#endif
-    ScanFoldersModel::initInstance(this);
-
-#ifndef DISABLE_WEBUI
-    m_webui = new WebUI;
-#ifdef DISABLE_GUI
-    if (m_webui->isErrored())
-        return 1;
-    connect(m_webui, &WebUI::fatalError, this, []() { QCoreApplication::exit(1); });
-#endif // DISABLE_GUI
-#endif // DISABLE_WEBUI
-
-    new RSS::Session; // create RSS::Session singleton
-    new RSS::AutoDownloader; // create RSS::AutoDownloader singleton
-
-#ifdef DISABLE_GUI
-#ifndef DISABLE_WEBUI
-    Preferences* const pref = Preferences::instance();
-    // Display some information to the user
-    const QString mesg = QString("\n******** %1 ********\n").arg(tr("Information"))
-        + tr("To control qBittorrent, access the Web UI at %1")
-            .arg(QString("http://localhost:") + QString::number(pref->getWebUiPort())) + '\n'
-        + tr("The Web UI administrator user name is: %1").arg(pref->getWebUiUsername()) + '\n';
-    printf("%s", qUtf8Printable(mesg));
-    qDebug() << "Password:" << pref->getWebUiPassword();
-    if (pref->getWebUiPassword() == "f6fdffe48c908deb0f4c3bd36c032e72") {
-        const QString warning = tr("The Web UI administrator password is still the default one: %1").arg("adminadmin") + '\n'
-            + tr("This is a security risk, please consider changing your password from program preferences.") + '\n';
-        printf("%s", qUtf8Printable(warning));
-    }
-#endif // DISABLE_WEBUI
-#else
+#ifndef DISABLE_GUI
     m_window = new MainWindow;
 #endif // DISABLE_GUI
 
-    m_running = true;
+    // Slots are executed in the order of connection.
+    // Thus we need this connected last.
+    connect(BitTorrent::Session::instance(), &BitTorrent::Session::startupFinished, this, &Application::handleStartUpFinished);
+
+    m_paramsQueue = params + m_paramsQueue;
 
     // Now UI is ready to process signals from Session
     BitTorrent::Session::instance()->startUpTorrents();
 
-    m_paramsQueue = params + m_paramsQueue;
-    if (!m_paramsQueue.isEmpty()) {
-        processParams(m_paramsQueue);
-        m_paramsQueue.clear();
-    }
     return BaseApplication::exec();
 }
 
@@ -758,3 +724,50 @@ void Application::validateCommandLineParameters()
     if (m_commandLineArgs.portableMode && m_commandLineArgs.relativeFastresumePaths)
         Logger::instance()->addMessage(tr("Portable mode implies relative fastresume"), Log::WARNING);
 }
+
+void Application::handleStartUpFinished()
+{
+#ifndef DISABLE_COUNTRIES_RESOLUTION
+    Net::GeoIPManager::initInstance();
+#endif
+    ScanFoldersModel::initInstance(this);
+
+#ifndef DISABLE_WEBUI
+    m_webui = new WebUI;
+#ifdef DISABLE_GUI
+    if (m_webui->isErrored())
+        QCoreApplication::exit(1);
+    connect(m_webui, &WebUI::fatalError, this, []() { QCoreApplication::exit(1); });
+#endif // DISABLE_GUI
+#endif // DISABLE_WEBUI
+
+    new RSS::Session; // create RSS::Session singleton
+    new RSS::AutoDownloader; // create RSS::AutoDownloader singleton
+
+#ifdef DISABLE_GUI
+#ifndef DISABLE_WEBUI
+    Preferences* const pref = Preferences::instance();
+    // Display some information to the user
+    const QString mesg = QString("\n******** %1 ********\n").arg(tr("Information"))
+        + tr("To control qBittorrent, access the Web UI at %1")
+            .arg(QString("http://localhost:") + QString::number(pref->getWebUiPort())) + '\n'
+        + tr("The Web UI administrator user name is: %1").arg(pref->getWebUiUsername()) + '\n';
+    printf("%s", qUtf8Printable(mesg));
+    qDebug() << "Password:" << pref->getWebUiPassword();
+    if (pref->getWebUiPassword() == "f6fdffe48c908deb0f4c3bd36c032e72") {
+        const QString warning = tr("The Web UI administrator password is still the default one: %1").arg("adminadmin") + '\n'
+            + tr("This is a security risk, please consider changing your password from program preferences.") + '\n';
+        printf("%s", qUtf8Printable(warning));
+    }
+#endif // DISABLE_WEBUI
+#else
+    m_window->setEnabledWidgets(true);
+#endif // DISABLE_GUI
+
+    m_running = true;
+
+    if (!m_paramsQueue.isEmpty()) {
+        processParams(m_paramsQueue);
+        m_paramsQueue.clear();
+    }
+}
diff --git a/src/app/application.h b/src/app/application.h
index 13517f48b..c945acc31 100644
--- a/src/app/application.h
+++ b/src/app/application.h
@@ -149,6 +149,7 @@ private:
     void runExternalProgram(const BitTorrent::TorrentHandle *torrent) const;
     void sendNotificationEmail(const BitTorrent::TorrentHandle *torrent);
     void validateCommandLineParameters();
+    void handleStartUpFinished();
 };
 
 #endif // APPLICATION_H
diff --git a/src/base/CMakeLists.txt b/src/base/CMakeLists.txt
index a9cdb45a5..490e0c36d 100644
--- a/src/base/CMakeLists.txt
+++ b/src/base/CMakeLists.txt
@@ -10,6 +10,7 @@ bittorrent/private/bandwidthscheduler.h
 bittorrent/private/filterparserthread.h
 bittorrent/private/resumedatasavingmanager.h
 bittorrent/private/speedmonitor.h
+bittorrent/private/startuptorrentsmanager.h
 bittorrent/private/statistics.h
 bittorrent/session.h
 bittorrent/sessionstatus.h
@@ -82,6 +83,7 @@ bittorrent/private/bandwidthscheduler.cpp
 bittorrent/private/filterparserthread.cpp
 bittorrent/private/resumedatasavingmanager.cpp
 bittorrent/private/speedmonitor.cpp
+bittorrent/private/startuptorrentsmanager.cpp
 bittorrent/private/statistics.cpp
 bittorrent/session.cpp
 bittorrent/torrentcreatorthread.cpp
diff --git a/src/base/base.pri b/src/base/base.pri
index c84c49c93..93c4b6e74 100644
--- a/src/base/base.pri
+++ b/src/base/base.pri
@@ -10,6 +10,7 @@ HEADERS += \
     $$PWD/bittorrent/private/filterparserthread.h \
     $$PWD/bittorrent/private/resumedatasavingmanager.h \
     $$PWD/bittorrent/private/speedmonitor.h \
+    $$PWD/bittorrent/private/startuptorrentsmanager.h \
     $$PWD/bittorrent/private/statistics.h \
     $$PWD/bittorrent/session.h \
     $$PWD/bittorrent/sessionstatus.h \
@@ -81,6 +82,7 @@ SOURCES += \
     $$PWD/bittorrent/private/filterparserthread.cpp \
     $$PWD/bittorrent/private/resumedatasavingmanager.cpp \
     $$PWD/bittorrent/private/speedmonitor.cpp \
+    $$PWD/bittorrent/private/startuptorrentsmanager.cpp \
     $$PWD/bittorrent/private/statistics.cpp \
     $$PWD/bittorrent/session.cpp \
     $$PWD/bittorrent/torrentcreatorthread.cpp \
diff --git a/src/base/bittorrent/private/startuptorrentsmanager.cpp b/src/base/bittorrent/private/startuptorrentsmanager.cpp
new file mode 100644
index 000000000..3dff99020
--- /dev/null
+++ b/src/base/bittorrent/private/startuptorrentsmanager.cpp
@@ -0,0 +1,242 @@
+/*
+ * Bittorrent Client using Qt and libtorrent.
+ * Copyright (C) 2018  sledgehammer999 <hammered999@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ * In addition, as a special exception, the copyright holders give permission to
+ * link this program with the OpenSSL project's "OpenSSL" library (or with
+ * modified versions of it that use the same license as the "OpenSSL" library),
+ * and distribute the linked executables. You must obey the GNU General Public
+ * License in all respects for all of the code used other than "OpenSSL".  If you
+ * modify file(s), you may extend this exception to your version of the file(s),
+ * but you are not obligated to do so. If you do not wish to do so, delete this
+ * exception statement from your version.
+ */
+
+#include "startuptorrentsmanager.h"
+
+#include "base/logger.h"
+#include "base/profile.h"
+#include "base/bittorrent/session.h"
+#include "base/utils/fs.h"
+
+#include <QDebug>
+#include <QMutexLocker>
+
+namespace libt = libtorrent;
+using namespace BitTorrent;
+
+namespace
+{
+    bool readFile(const QString &path, QByteArray &buf);
+    bool loadTorrentResumeData(const QByteArray &data, AddTorrentData &torrentData, int &prio, MagnetUri &magnetUri);
+}
+
+StartUpTorrentsManager::StartUpTorrentsManager(const QString &resumeFolderPath)
+    : m_signaledReady(false)
+    , m_lock(QMutex::Recursive)
+    , m_resumeDataDir(resumeFolderPath)
+{
+}
+
+void StartUpTorrentsManager::loadTorrents()
+{
+    QStringList fastresumes = m_resumeDataDir.entryList(
+                QStringList(QLatin1String("*.fastresume")), QDir::Files, QDir::Unsorted);
+
+    Logger *const logger = Logger::instance();
+
+    int loadedCount = 0;
+    int nextQueuePosition = 1;
+    int numOfRemappedFiles = 0;
+    QRegExp rx(QLatin1String("^([A-Fa-f0-9]{40})\\.fastresume$"));
+    foreach (const QString &fastresumeName, fastresumes) {
+        if (rx.indexIn(fastresumeName) == -1) continue;
+
+        QString hash = rx.cap(1);
+        QString fastresumePath = m_resumeDataDir.absoluteFilePath(fastresumeName);
+        QByteArray data;
+        AddTorrentData resumeData;
+        MagnetUri magnetUri;
+        int queuePosition;
+        if (readFile(fastresumePath, data) && loadTorrentResumeData(data, resumeData, queuePosition, magnetUri)) {
+            ++loadedCount;
+            QString filePath = m_resumeDataDir.filePath(QString("%1.torrent").arg(hash));
+
+            if (queuePosition <= nextQueuePosition) {
+                QMutexLocker locker(&m_lock);
+                readyResumeData.push_back({hash, magnetUri, resumeData, TorrentInfo::loadFromFile(filePath), data});
+
+                if (queuePosition == nextQueuePosition) {
+                    ++nextQueuePosition;
+                    while (queuedResumeData.contains(nextQueuePosition)) {
+                        readyResumeData.push_back(queuedResumeData.take(nextQueuePosition));
+                        ++nextQueuePosition;
+                    }
+                }
+
+                if (!m_signaledReady) {
+                    emit readyRead();
+                    m_signaledReady = true;
+                }
+            }
+            else {
+                int q = queuePosition;
+                for (; queuedResumeData.contains(q); ++q) {
+                }
+                if (q != queuePosition) {
+                    ++numOfRemappedFiles;
+                }
+                queuedResumeData[q] = {hash, magnetUri, resumeData, TorrentInfo::loadFromFile(filePath), data};
+            }
+        }
+    }
+
+    if (numOfRemappedFiles > 0) {
+        logger->addMessage(
+            QString(tr("Queue positions were corrected in %1 resume files")).arg(numOfRemappedFiles),
+            Log::CRITICAL);
+    }
+
+    // readyresumeData might not have been emptied by the main thread yet
+    // so we need to append to that
+    QMutexLocker locker(&m_lock);
+    auto begin = queuedResumeData.cbegin();
+    auto end = queuedResumeData.cend();
+    for (; begin != end; ++begin)
+        readyResumeData.push_back(begin.value());
+    queuedResumeData.clear();
+
+    if (!m_signaledReady) {
+        emit readyRead();
+        m_signaledReady = true;
+    }
+
+    emit finished(loadedCount);
+}
+
+void StartUpTorrentsManager::resumeData(QVector<TorrentResumeData> &out)
+{
+    QMutexLocker locker(&m_lock);
+    out.clear();
+    readyResumeData.swap(out);
+    m_signaledReady = false;
+}
+
+namespace
+{
+    template <typename Entry>
+    QSet<QString> entryListToSetImpl(const Entry &entry)
+    {
+        Q_ASSERT(entry.type() == Entry::list_t);
+        QSet<QString> output;
+        for (int i = 0; i < entry.list_size(); ++i) {
+            const QString tag = QString::fromStdString(entry.list_string_value_at(i));
+            if (Session::isValidTag(tag))
+                output.insert(tag);
+            else
+                qWarning() << QString("Dropping invalid stored tag: %1").arg(tag);
+        }
+        return output;
+    }
+
+#if LIBTORRENT_VERSION_NUM < 10100
+    bool isList(const libt::lazy_entry *entry)
+    {
+        return entry && (entry->type() == libt::lazy_entry::list_t);
+    }
+
+    QSet<QString> entryListToSet(const libt::lazy_entry *entry)
+    {
+        return entry ? entryListToSetImpl(*entry) : QSet<QString>();
+    }
+#else
+    bool isList(const libt::bdecode_node &entry)
+    {
+        return entry.type() == libt::bdecode_node::list_t;
+    }
+
+    QSet<QString> entryListToSet(const libt::bdecode_node &entry)
+    {
+        return entryListToSetImpl(entry);
+    }
+#endif
+
+    bool readFile(const QString &path, QByteArray &buf)
+    {
+        QFile file(path);
+        if (!file.open(QIODevice::ReadOnly)) {
+            qDebug("Cannot read file %s: %s", qUtf8Printable(path), qUtf8Printable(file.errorString()));
+            return false;
+        }
+
+        buf = file.readAll();
+        return true;
+    }
+
+    bool loadTorrentResumeData(const QByteArray &data, AddTorrentData &torrentData, int &prio,  MagnetUri &magnetUri)
+    {
+        torrentData = AddTorrentData();
+        torrentData.resumed = true;
+        torrentData.skipChecking = false;
+
+        libt::error_code ec;
+#if LIBTORRENT_VERSION_NUM < 10100
+        libt::lazy_entry fast;
+        libt::lazy_bdecode(data.constData(), data.constData() + data.size(), fast, ec);
+        if (ec || (fast.type() != libt::lazy_entry::dict_t)) return false;
+#else
+        libt::bdecode_node fast;
+        libt::bdecode(data.constData(), data.constData() + data.size(), fast, ec);
+        if (ec || (fast.type() != libt::bdecode_node::dict_t)) return false;
+#endif
+
+        torrentData.savePath = Profile::instance().fromPortablePath(
+                                   Utils::Fs::fromNativePath(QString::fromStdString(fast.dict_find_string_value("qBt-savePath"))));
+
+        std::string ratioLimitString = fast.dict_find_string_value("qBt-ratioLimit");
+        if (ratioLimitString.empty())
+            torrentData.ratioLimit = fast.dict_find_int_value("qBt-ratioLimit", TorrentHandle::USE_GLOBAL_RATIO * 1000) / 1000.0;
+        else
+            torrentData.ratioLimit = QString::fromStdString(ratioLimitString).toDouble();
+        torrentData.seedingTimeLimit = fast.dict_find_int_value("qBt-seedingTimeLimit", TorrentHandle::USE_GLOBAL_SEEDING_TIME);
+        // **************************************************************************************
+        // Workaround to convert legacy label to category
+        // TODO: Should be removed in future
+        torrentData.category = QString::fromStdString(fast.dict_find_string_value("qBt-label"));
+        if (torrentData.category.isEmpty())
+            // **************************************************************************************
+            torrentData.category = QString::fromStdString(fast.dict_find_string_value("qBt-category"));
+        // auto because the return type depends on the #if above.
+        const auto tagsEntry = fast.dict_find_list("qBt-tags");
+        if (isList(tagsEntry))
+            torrentData.tags = entryListToSet(tagsEntry);
+        torrentData.name = QString::fromStdString(fast.dict_find_string_value("qBt-name"));
+        torrentData.hasSeedStatus = fast.dict_find_int_value("qBt-seedStatus");
+        torrentData.disableTempPath = fast.dict_find_int_value("qBt-tempPathDisabled");
+        torrentData.hasRootFolder = fast.dict_find_int_value("qBt-hasRootFolder");
+
+        magnetUri = MagnetUri(QString::fromStdString(fast.dict_find_string_value("qBt-magnetUri")));
+        torrentData.addPaused = fast.dict_find_int_value("qBt-paused");
+        torrentData.addForced = fast.dict_find_int_value("qBt-forced");
+        torrentData.firstLastPiecePriority = fast.dict_find_int_value("qBt-firstLastPiecePriority");
+        torrentData.sequential = fast.dict_find_int_value("qBt-sequential");
+
+        prio = fast.dict_find_int_value("qBt-queuePosition");
+
+        return true;
+    }
+}
diff --git a/src/base/bittorrent/private/startuptorrentsmanager.h b/src/base/bittorrent/private/startuptorrentsmanager.h
new file mode 100644
index 000000000..3e1dbbfb0
--- /dev/null
+++ b/src/base/bittorrent/private/startuptorrentsmanager.h
@@ -0,0 +1,72 @@
+/*
+ * Bittorrent Client using Qt and libtorrent.
+ * Copyright (C) 2018  sledgehammer999 <hammered999@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ * In addition, as a special exception, the copyright holders give permission to
+ * link this program with the OpenSSL project's "OpenSSL" library (or with
+ * modified versions of it that use the same license as the "OpenSSL" library),
+ * and distribute the linked executables. You must obey the GNU General Public
+ * License in all respects for all of the code used other than "OpenSSL".  If you
+ * modify file(s), you may extend this exception to your version of the file(s),
+ * but you are not obligated to do so. If you do not wish to do so, delete this
+ * exception statement from your version.
+ */
+
+#pragma once
+
+#include "base/bittorrent/magneturi.h"
+#include "base/bittorrent/torrentinfo.h"
+#include "base/bittorrent/torrenthandle.h"
+
+#include <QDir>
+#include <QMap>
+#include <QMutex>
+#include <QObject>
+#include <QVector>
+
+
+class StartUpTorrentsManager : public QObject
+{
+    Q_OBJECT
+
+public:
+    struct TorrentResumeData
+    {
+        QString hash;
+        BitTorrent::MagnetUri magnetUri;
+        BitTorrent::AddTorrentData addTorrentData;
+        BitTorrent::TorrentInfo info;
+        QByteArray data;
+    };
+
+    explicit StartUpTorrentsManager(const QString &resumeFolderPath);
+    void resumeData(QVector<TorrentResumeData> &out);
+
+signals:
+    void readyRead();
+    void finished(int loadedCount);
+
+public slots:
+    void loadTorrents();
+
+private:
+    bool m_signaledReady;
+    mutable QMutex m_lock;
+    QDir m_resumeDataDir;
+    QVector<TorrentResumeData> readyResumeData;
+    QMap<int, TorrentResumeData> queuedResumeData;
+};
diff --git a/src/base/bittorrent/session.cpp b/src/base/bittorrent/session.cpp
index d5b8cdd0c..5120e0617 100644
--- a/src/base/bittorrent/session.cpp
+++ b/src/base/bittorrent/session.cpp
@@ -88,6 +88,7 @@
 #include "private/bandwidthscheduler.h"
 #include "private/filterparserthread.h"
 #include "private/resumedatasavingmanager.h"
+#include "private/startuptorrentsmanager.h"
 #include "private/statistics.h"
 #include "torrenthandle.h"
 #include "tracker.h"
@@ -111,9 +112,6 @@ using namespace BitTorrent;
 
 namespace
 {
-    bool readFile(const QString &path, QByteArray &buf);
-    bool loadTorrentResumeData(const QByteArray &data, AddTorrentData &torrentData, int &prio, MagnetUri &magnetUri);
-
     void torrentQueuePositionUp(const libt::torrent_handle &handle);
     void torrentQueuePositionDown(const libt::torrent_handle &handle);
     void torrentQueuePositionTop(const libt::torrent_handle &handle);
@@ -139,43 +137,6 @@ namespace
         return result;
     }
 
-    template <typename Entry>
-    QSet<QString> entryListToSetImpl(const Entry &entry)
-    {
-        Q_ASSERT(entry.type() == Entry::list_t);
-        QSet<QString> output;
-        for (int i = 0; i < entry.list_size(); ++i) {
-            const QString tag = QString::fromStdString(entry.list_string_value_at(i));
-            if (Session::isValidTag(tag))
-                output.insert(tag);
-            else
-                qWarning() << QString("Dropping invalid stored tag: %1").arg(tag);
-        }
-        return output;
-    }
-
-#if LIBTORRENT_VERSION_NUM < 10100
-    bool isList(const libt::lazy_entry *entry)
-    {
-        return entry && (entry->type() == libt::lazy_entry::list_t);
-    }
-
-    QSet<QString> entryListToSet(const libt::lazy_entry *entry)
-    {
-        return entry ? entryListToSetImpl(*entry) : QSet<QString>();
-    }
-#else
-    bool isList(const libt::bdecode_node &entry)
-    {
-        return entry.type() == libt::bdecode_node::list_t;
-    }
-
-    QSet<QString> entryListToSet(const libt::bdecode_node &entry)
-    {
-        return entryListToSetImpl(entry);
-    }
-#endif
-
     QString normalizePath(const QString &path)
     {
         QString tmp = Utils::Fs::fromNativePath(path.trimmed());
@@ -371,6 +332,9 @@ Session::Session(QObject *parent)
     , m_extraLimit(0)
     , m_useProxy(false)
     , m_recentErroredTorrentsTimer(new QTimer(this))
+    , m_startedCount(0)
+    , m_loadedCount(0)
+    , m_startupInProgress(false)
 {
     Logger *const logger = Logger::instance();
 
@@ -385,15 +349,7 @@ Session::Session(QObject *parent)
     connect(m_seedingLimitTimer, &QTimer::timeout, this, &Session::processShareLimits);
 
     // Set severity level of libtorrent session
-    const int alertMask = libt::alert::error_notification
-                    | libt::alert::peer_notification
-                    | libt::alert::port_mapping_notification
-                    | libt::alert::storage_notification
-                    | libt::alert::tracker_notification
-                    | libt::alert::status_notification
-                    | libt::alert::ip_block_notification
-                    | libt::alert::progress_notification
-                    | libt::alert::stats_notification;
+    const int alertMask = libt::alert::status_notification;
 
 #if LIBTORRENT_VERSION_NUM < 10100
     libt::fingerprint fingerprint(PEER_ID, QBT_VERSION_MAJOR, QBT_VERSION_MINOR, QBT_VERSION_BUGFIX, QBT_VERSION_BUILD);
@@ -466,6 +422,7 @@ Session::Session(QObject *parent)
     configurePeerClasses();
 #endif
 
+    m_nativeSession->pause();
     // Enabling plugins
     //m_nativeSession->add_extension(&libt::create_metadata_plugin);
     m_nativeSession->add_extension(&libt::create_ut_metadata_plugin);
@@ -483,9 +440,6 @@ Session::Session(QObject *parent)
                        .arg(encryption() == 0 ? tr("ON") : encryption() == 1 ? tr("FORCED") : tr("OFF"))
                        , Log::INFO);
 
-    if (isBandwidthSchedulerEnabled())
-        enableBandwidthScheduler();
-
     if (isIPFilteringEnabled()) {
         // Manually banned IPs are handled in that function too(in the slots)
         enableIPFilter();
@@ -509,7 +463,6 @@ Session::Session(QObject *parent)
     m_refreshTimer = new QTimer(this);
     m_refreshTimer->setInterval(refreshInterval());
     connect(m_refreshTimer, &QTimer::timeout, this, &Session::refresh);
-    m_refreshTimer->start();
 
     // Regular saving of fastresume data
     m_resumeDataTimer = new QTimer(this);
@@ -517,10 +470,7 @@ Session::Session(QObject *parent)
     connect(m_resumeDataTimer, &QTimer::timeout, this, [this]() { generateResumeData(); });
 
     m_statistics = new Statistics(this);
-
-    updateSeedingLimitTimer();
     populateAdditionalTrackers();
-
     enableTracker(isTrackerEnabled());
 
     connect(Net::ProxyConfigurationManager::instance(), &Net::ProxyConfigurationManager::proxyConfigurationChanged
@@ -537,14 +487,18 @@ Session::Session(QObject *parent)
     m_resumeDataSavingManager->moveToThread(m_ioThread);
     connect(m_ioThread, &QThread::finished, m_resumeDataSavingManager, &QObject::deleteLater);
     m_ioThread->start();
-    m_resumeDataTimer->start();
+
+    m_startupThread = new QThread(this);
+    m_startUpTorrentsManager = new StartUpTorrentsManager(m_resumeFolderPath);
+    m_startUpTorrentsManager->moveToThread(m_startupThread);
+    connect(m_startupThread, &QThread::finished, m_startUpTorrentsManager, &QObject::deleteLater);
+    m_startupThread->start();
 
     // initialize PortForwarder instance
     Net::PortForwarder::initInstance(m_nativeSession);
 
 #if LIBTORRENT_VERSION_NUM >= 10100
     initMetrics();
-    m_statsUpdateTimer.start();
 #endif
 
     qDebug("* BitTorrent Session constructed");
@@ -996,6 +950,9 @@ Session::~Session()
     m_ioThread->quit();
     m_ioThread->wait();
 
+    m_startupThread->quit();
+    m_startupThread->wait();
+
     m_resumeFolderLock.close();
     m_resumeFolderLock.remove();
 }
@@ -1349,11 +1306,7 @@ void Session::configure(libtorrent::settings_pack &settingsPack)
     settingsPack.set_int(libt::settings_pack::active_tracker_limit, -1);
     settingsPack.set_int(libt::settings_pack::active_dht_limit, -1);
     settingsPack.set_int(libt::settings_pack::active_lsd_limit, -1);
-    // 1 active torrent force 2 connections. If you have more active torrents * 2 than connection limit,
-    // connection limit will get extended. Multiply max connections or active torrents by 10 for queue.
-    // Ignore -1 values because we don't want to set a max int message queue
-    settingsPack.set_int(libt::settings_pack::alert_queue_size, std::max(1000,
-        10 * std::max(maxActiveTorrents() * 2, maxConnections())));
+    settingsPack.set_int(libt::settings_pack::alert_queue_size, 1000000);
 
     // Outgoing ports
     settingsPack.set_int(libt::settings_pack::outgoing_port, outgoingPortsMin());
@@ -1628,11 +1581,7 @@ void Session::configure(libtorrent::session_settings &sessionSettings)
     sessionSettings.active_tracker_limit = -1;
     sessionSettings.active_dht_limit = -1;
     sessionSettings.active_lsd_limit = -1;
-    // 1 active torrent force 2 connections. If you have more active torrents * 2 than connection limit,
-    // connection limit will get extended. Multiply max connections or active torrents by 10 for queue.
-    // Ignore -1 values because we don't want to set a max int message queue
-    sessionSettings.alert_queue_size = std::max(1000,
-        10 * std::max(maxActiveTorrents() * 2, maxConnections()));
+    sessionSettings.alert_queue_size = 1000000;
 
     // Outgoing ports
     sessionSettings.outgoing_ports = std::make_pair(outgoingPortsMin(), outgoingPortsMax());
@@ -3794,84 +3743,38 @@ void Session::startUpTorrents()
 {
     qDebug("Resuming torrents...");
 
-    const QDir resumeDataDir(m_resumeFolderPath);
-    QStringList fastresumes = resumeDataDir.entryList(
-                QStringList(QLatin1String("*.fastresume")), QDir::Files, QDir::Unsorted);
-
-    Logger *const logger = Logger::instance();
+    m_startupInProgress = true;
 
-    typedef struct
+    const auto startupTorrent = [this]()
     {
-        QString hash;
-        MagnetUri magnetUri;
-        AddTorrentData addTorrentData;
-        QByteArray data;
-    } TorrentResumeData;
-
-    int resumedTorrentsCount = 0;
-    const auto startupTorrent = [this, logger, &resumeDataDir, &resumedTorrentsCount](const TorrentResumeData &params)
-    {
-        QString filePath = resumeDataDir.filePath(QString("%1.torrent").arg(params.hash));
-        qDebug() << "Starting up torrent" << params.hash << "...";
-        if (!addTorrent_impl(params.addTorrentData, params.magnetUri, TorrentInfo::loadFromFile(filePath), params.data))
-            logger->addMessage(tr("Unable to resume torrent '%1'.", "e.g: Unable to resume torrent 'hash'.")
-                               .arg(params.hash), Log::CRITICAL);
+        int resumedTorrentsCount = 0;
+        QVector<StartUpTorrentsManager::TorrentResumeData> resumeData;
+        m_startUpTorrentsManager->resumeData(resumeData);
 
-        // process add torrent messages before message queue overflow
-        if ((resumedTorrentsCount % 100) == 0) readAlerts();
+        for (const auto rd : resumeData) {
+            qDebug() << "Starting up torrent" << rd.hash << "...";
+            if (!addTorrent_impl(rd.addTorrentData, rd.magnetUri, rd.info, rd.data))
+                LogMsg(tr("Unable to resume torrent '%1'.", "e.g: Unable to resume torrent 'hash'.")
+                                   .arg(rd.hash), Log::CRITICAL);
 
-        ++resumedTorrentsCount;
-    };
+            // process add torrent messages before message queue overflow
+            if ((resumedTorrentsCount % 100) == 0) readAlerts();
 
-    qDebug("Starting up torrents");
-    qDebug("Queue size: %d", fastresumes.size());
-    // Resume downloads
-    QMap<int, TorrentResumeData> queuedResumeData;
-    int nextQueuePosition = 1;
-    int numOfRemappedFiles = 0;
-    QRegExp rx(QLatin1String("^([A-Fa-f0-9]{40})\\.fastresume$"));
-    foreach (const QString &fastresumeName, fastresumes) {
-        if (rx.indexIn(fastresumeName) == -1) continue;
-
-        QString hash = rx.cap(1);
-        QString fastresumePath = resumeDataDir.absoluteFilePath(fastresumeName);
-        QByteArray data;
-        AddTorrentData resumeData;
-        MagnetUri magnetUri;
-        int queuePosition;
-        if (readFile(fastresumePath, data) && loadTorrentResumeData(data, resumeData, queuePosition, magnetUri)) {
-            if (queuePosition <= nextQueuePosition) {
-                startupTorrent({ hash, magnetUri, resumeData, data });
-
-                if (queuePosition == nextQueuePosition) {
-                    ++nextQueuePosition;
-                    while (queuedResumeData.contains(nextQueuePosition)) {
-                        startupTorrent(queuedResumeData.take(nextQueuePosition));
-                        ++nextQueuePosition;
-                    }
-                }
-            }
-            else {
-                int q = queuePosition;
-                for (; queuedResumeData.contains(q); ++q) {
-                }
-                if (q != queuePosition) {
-                    ++numOfRemappedFiles;
-                }
-                queuedResumeData[q] = {hash, magnetUri, resumeData, data};
-            }
+            ++resumedTorrentsCount;
         }
-    }
+    };
 
-    if (numOfRemappedFiles > 0) {
-        logger->addMessage(
-            QString(tr("Queue positions were corrected in %1 resume files")).arg(numOfRemappedFiles),
-            Log::CRITICAL);
-    }
+    const auto torrentsLoaded = [this](int loadedCount)
+    {
+        m_loadedCount = loadedCount;
+        if (m_startedCount == m_loadedCount)
+            handleStartUpFinished();
+    };
 
-    // starting up downloading torrents (queue position > 0)
-    foreach (const TorrentResumeData &torrentResumeData, queuedResumeData)
-        startupTorrent(torrentResumeData);
+    connect(m_startUpTorrentsManager, &StartUpTorrentsManager::readyRead, this, startupTorrent);
+    connect(m_startUpTorrentsManager, &StartUpTorrentsManager::finished, this, torrentsLoaded);
+
+    QMetaObject::invokeMethod(m_startUpTorrentsManager, "loadTorrents");
 }
 
 quint64 Session::getAlltimeDL() const
@@ -4009,6 +3912,9 @@ void Session::handleAlert(libt::alert *a)
         case libt::add_torrent_alert::alert_type:
             handleAddTorrentAlert(static_cast<libt::add_torrent_alert*>(a));
             break;
+        case libt::torrent_added_alert::alert_type:
+            handleTorrentAddedAlert();
+            break;
         case libt::torrent_removed_alert::alert_type:
             handleTorrentRemovedAlert(static_cast<libt::torrent_removed_alert*>(a));
             break;
@@ -4113,8 +4019,9 @@ void Session::createTorrentHandle(const libt::torrent_handle &nativeHandle)
         && !m_seedingLimitTimer->isActive())
         m_seedingLimitTimer->start();
 
-    // Send torrent addition signal
-    emit torrentAdded(torrent);
+    // Send torrent addition signal only if we're not starting up
+    if (!m_startupInProgress)
+        emit torrentAdded(torrent);
     // Send new torrent signal
     if (!data.resumed)
         emit torrentNew(torrent);
@@ -4124,6 +4031,7 @@ void Session::handleAddTorrentAlert(libt::add_torrent_alert *p)
 {
     if (p->error) {
         qDebug("/!\\ Error: Failed to add torrent!");
+        if (m_startupInProgress) ++m_startedCount;
         QString msg = QString::fromStdString(p->message());
         Logger::instance()->addMessage(tr("Couldn't add torrent. Reason: %1").arg(msg), Log::WARNING);
         emit addTorrentFailed(msg);
@@ -4133,6 +4041,14 @@ void Session::handleAddTorrentAlert(libt::add_torrent_alert *p)
     }
 }
 
+void Session::handleTorrentAddedAlert()
+{
+    if (!m_startupInProgress) return;
+    ++m_startedCount;
+    if (m_startedCount == m_loadedCount)
+        handleStartUpFinished();
+}
+
 void Session::handleTorrentRemovedAlert(libt::torrent_removed_alert *p)
 {
     if (m_loadedMetadata.contains(p->info_hash))
@@ -4313,6 +4229,40 @@ void Session::handleExternalIPAlert(libt::external_ip_alert *p)
     Logger::instance()->addMessage(tr("External IP: %1", "e.g. External IP: 192.168.0.1").arg(p->external_address.to_string(ec).c_str()), Log::INFO);
 }
 
+void Session::handleStartUpFinished()
+{
+    m_startupInProgress = false;
+    m_startupThread->quit();
+
+    if (isBandwidthSchedulerEnabled())
+        enableBandwidthScheduler();
+    m_refreshTimer->start();
+    m_resumeDataTimer->start();
+#if LIBTORRENT_VERSION_NUM >= 10100
+    m_statsUpdateTimer.start();
+#endif
+    updateSeedingLimitTimer();
+    const int alertMask = libt::alert::error_notification
+                          | libt::alert::peer_notification
+                          | libt::alert::port_mapping_notification
+                          | libt::alert::storage_notification
+                          | libt::alert::tracker_notification
+                          | libt::alert::status_notification
+                          | libt::alert::ip_block_notification
+                          | libt::alert::progress_notification
+                          | libt::alert::stats_notification;
+
+#if LIBTORRENT_VERSION_NUM < 10100
+    m_nativeSession->set_alert_mask(alertMask);
+#else
+    libt::settings_pack pack = m_nativeSession->get_settings();
+    pack.set_int(libt::settings_pack::alert_mask, alertMask);
+    m_nativeSession->apply_settings(pack);
+#endif
+    m_nativeSession->resume();
+    emit startupFinished();
+}
+
 #if LIBTORRENT_VERSION_NUM >= 10100
 void Session::handleSessionStatsAlert(libt::session_stats_alert *p)
 {
@@ -4454,71 +4404,6 @@ void Session::handleStateUpdateAlert(libt::state_update_alert *p)
 
 namespace
 {
-    bool readFile(const QString &path, QByteArray &buf)
-    {
-        QFile file(path);
-        if (!file.open(QIODevice::ReadOnly)) {
-            qDebug("Cannot read file %s: %s", qUtf8Printable(path), qUtf8Printable(file.errorString()));
-            return false;
-        }
-
-        buf = file.readAll();
-        return true;
-    }
-
-    bool loadTorrentResumeData(const QByteArray &data, AddTorrentData &torrentData, int &prio,  MagnetUri &magnetUri)
-    {
-        torrentData = AddTorrentData();
-        torrentData.resumed = true;
-        torrentData.skipChecking = false;
-
-        libt::error_code ec;
-#if LIBTORRENT_VERSION_NUM < 10100
-        libt::lazy_entry fast;
-        libt::lazy_bdecode(data.constData(), data.constData() + data.size(), fast, ec);
-        if (ec || (fast.type() != libt::lazy_entry::dict_t)) return false;
-#else
-        libt::bdecode_node fast;
-        libt::bdecode(data.constData(), data.constData() + data.size(), fast, ec);
-        if (ec || (fast.type() != libt::bdecode_node::dict_t)) return false;
-#endif
-
-        torrentData.savePath = Profile::instance().fromPortablePath(
-            Utils::Fs::fromNativePath(QString::fromStdString(fast.dict_find_string_value("qBt-savePath"))));
-
-        std::string ratioLimitString = fast.dict_find_string_value("qBt-ratioLimit");
-        if (ratioLimitString.empty())
-            torrentData.ratioLimit = fast.dict_find_int_value("qBt-ratioLimit", TorrentHandle::USE_GLOBAL_RATIO * 1000) / 1000.0;
-        else
-            torrentData.ratioLimit = QString::fromStdString(ratioLimitString).toDouble();
-        torrentData.seedingTimeLimit = fast.dict_find_int_value("qBt-seedingTimeLimit", TorrentHandle::USE_GLOBAL_SEEDING_TIME);
-        // **************************************************************************************
-        // Workaround to convert legacy label to category
-        // TODO: Should be removed in future
-        torrentData.category = QString::fromStdString(fast.dict_find_string_value("qBt-label"));
-        if (torrentData.category.isEmpty())
-        // **************************************************************************************
-            torrentData.category = QString::fromStdString(fast.dict_find_string_value("qBt-category"));
-        // auto because the return type depends on the #if above.
-        const auto tagsEntry = fast.dict_find_list("qBt-tags");
-        if (isList(tagsEntry))
-            torrentData.tags = entryListToSet(tagsEntry);
-        torrentData.name = QString::fromStdString(fast.dict_find_string_value("qBt-name"));
-        torrentData.hasSeedStatus = fast.dict_find_int_value("qBt-seedStatus");
-        torrentData.disableTempPath = fast.dict_find_int_value("qBt-tempPathDisabled");
-        torrentData.hasRootFolder = fast.dict_find_int_value("qBt-hasRootFolder");
-
-        magnetUri = MagnetUri(QString::fromStdString(fast.dict_find_string_value("qBt-magnetUri")));
-        torrentData.addPaused = fast.dict_find_int_value("qBt-paused");
-        torrentData.addForced = fast.dict_find_int_value("qBt-forced");
-        torrentData.firstLastPiecePriority = fast.dict_find_int_value("qBt-firstLastPiecePriority");
-        torrentData.sequential = fast.dict_find_int_value("qBt-sequential");
-
-        prio = fast.dict_find_int_value("qBt-queuePosition");
-
-        return true;
-    }
-
     void torrentQueuePositionUp(const libt::torrent_handle &handle)
     {
         try {
diff --git a/src/base/bittorrent/session.h b/src/base/bittorrent/session.h
index dec225a73..f942aaa45 100644
--- a/src/base/bittorrent/session.h
+++ b/src/base/bittorrent/session.h
@@ -118,6 +118,7 @@ class FilterParserThread;
 class BandwidthScheduler;
 class Statistics;
 class ResumeDataSavingManager;
+class StartUpTorrentsManager;
 
 enum MaxRatioAction
 {
@@ -538,6 +539,7 @@ namespace BitTorrent
         void subcategoriesSupportChanged();
         void tagAdded(const QString &tag);
         void tagRemoved(const QString &tag);
+        void startupFinished();
 
     private slots:
         void configureDeferred();
@@ -607,6 +609,7 @@ namespace BitTorrent
         void handleAlert(libtorrent::alert *a);
         void dispatchTorrentAlert(libtorrent::alert *a);
         void handleAddTorrentAlert(libtorrent::add_torrent_alert *p);
+        void handleTorrentAddedAlert();
         void handleStateUpdateAlert(libtorrent::state_update_alert *p);
         void handleMetadataReceivedAlert(libtorrent::metadata_received_alert *p);
         void handleFileErrorAlert(libtorrent::file_error_alert *p);
@@ -621,6 +624,7 @@ namespace BitTorrent
         void handleListenSucceededAlert(libtorrent::listen_succeeded_alert *p);
         void handleListenFailedAlert(libtorrent::listen_failed_alert *p);
         void handleExternalIPAlert(libtorrent::external_ip_alert *p);
+        void handleStartUpFinished();
 #if LIBTORRENT_VERSION_NUM >= 10100
         void handleSessionStatsAlert(libtorrent::session_stats_alert *p);
 #endif
@@ -751,6 +755,9 @@ namespace BitTorrent
         // fastresume data writing thread
         QThread *m_ioThread;
         ResumeDataSavingManager *m_resumeDataSavingManager;
+        // fastresume data loading thread
+        QThread *m_startupThread;
+        StartUpTorrentsManager *m_startUpTorrentsManager;
 
         QHash<InfoHash, TorrentInfo> m_loadedMetadata;
         QHash<InfoHash, TorrentHandle *> m_torrents;
@@ -765,6 +772,11 @@ namespace BitTorrent
         QSet<InfoHash> m_recentErroredTorrents;
         QTimer *m_recentErroredTorrentsTimer;
 
+        // Used in starting up
+        int m_startedCount;
+        int m_loadedCount;
+        bool m_startupInProgress;
+
 #if LIBTORRENT_VERSION_NUM < 10100
         QMutex m_alertsMutex;
         QWaitCondition m_alertsWaitCondition;
diff --git a/src/base/bittorrent/torrenthandle.cpp b/src/base/bittorrent/torrenthandle.cpp
index 509fa67bd..15f13c429 100644
--- a/src/base/bittorrent/torrenthandle.cpp
+++ b/src/base/bittorrent/torrenthandle.cpp
@@ -1646,20 +1646,18 @@ void TorrentHandle::handleSaveResumeDataFailedAlert(const libtorrent::save_resum
 
 void TorrentHandle::handleFastResumeRejectedAlert(const libtorrent::fastresume_rejected_alert *p)
 {
-    qDebug("/!\\ Fast resume failed for %s, reason: %s", qUtf8Printable(name()), p->message().c_str());
-
-    updateStatus();
     if (p->error.value() == libt::errors::mismatching_file_size) {
         // Mismatching file size (files were probably moved)
-        LogMsg(tr("File sizes mismatch for torrent '%1', pausing it.").arg(name()), Log::CRITICAL);
+        pause();
         m_hasMissingFiles = true;
-        if (!isPaused())
-            pause();
+        LogMsg(tr("File sizes mismatch for torrent '%1', pausing it.").arg(name()), Log::CRITICAL);
     }
     else {
         LogMsg(tr("Fast resume data was rejected for torrent '%1'. Reason: %2. Checking again...")
             .arg(name(), QString::fromStdString(p->message())), Log::CRITICAL);
     }
+
+    updateStatus();
 }
 
 void TorrentHandle::handleFileRenamedAlert(const libtorrent::file_renamed_alert *p)
diff --git a/src/gui/categoryfiltermodel.cpp b/src/gui/categoryfiltermodel.cpp
index 85b4bf30f..f85bcaa1f 100644
--- a/src/gui/categoryfiltermodel.cpp
+++ b/src/gui/categoryfiltermodel.cpp
@@ -181,6 +181,12 @@ CategoryFilterModel::CategoryFilterModel(QObject *parent)
     connect(session, &Session::categoryRemoved, this, &CategoryFilterModel::categoryRemoved);
     connect(session, &Session::torrentCategoryChanged, this, &CategoryFilterModel::torrentCategoryChanged);
     connect(session, &Session::subcategoriesSupportChanged, this, &CategoryFilterModel::subcategoriesSupportChanged);
+    connect(session, &Session::startupFinished, this,
+            [this, session]()
+    {
+        for (const auto &handle : session->torrents().values())
+            torrentAdded(handle);
+    });
     connect(session, &Session::torrentAdded, this, &CategoryFilterModel::torrentAdded);
     connect(session, &Session::torrentAboutToBeRemoved, this, &CategoryFilterModel::torrentAboutToBeRemoved);
 
diff --git a/src/gui/mainwindow.cpp b/src/gui/mainwindow.cpp
index 61e48b19e..40350a120 100644
--- a/src/gui/mainwindow.cpp
+++ b/src/gui/mainwindow.cpp
@@ -150,6 +150,7 @@ MainWindow::MainWindow(QWidget *parent)
     , m_wasUpdateCheckEnabled(false)
 #endif
     , m_hasPython(false)
+    , m_sessionStarted(false)
 {
     m_ui->setupUi(this);
 
@@ -370,7 +371,6 @@ MainWindow::MainWindow(QWidget *parent)
     m_ui->actionWarningMessages->setChecked(flags & Log::WARNING);
     m_ui->actionCriticalMessages->setChecked(flags & Log::CRITICAL);
 
-    displayRSSTab(m_ui->actionRSSReader->isChecked());
     on_actionExecutionLogs_triggered(m_ui->actionExecutionLogs->isChecked());
     on_actionNormalMessages_triggered(m_ui->actionNormalMessages->isChecked());
     on_actionInformationMessages_triggered(m_ui->actionInformationMessages->isChecked());
@@ -466,6 +466,8 @@ MainWindow::MainWindow(QWidget *parent)
     setupDockClickHandler();
     qt_mac_set_dock_menu(trayIconMenu());
 #endif
+
+    setEnabledWidgets(false);
 }
 
 MainWindow::~MainWindow()
@@ -1295,8 +1297,11 @@ void MainWindow::dropEvent(QDropEvent *event)
 // Decode if we accept drag 'n drop or not
 void MainWindow::dragEnterEvent(QDragEnterEvent *event)
 {
-    foreach (const QString &mime, event->mimeData()->formats())
-        qDebug("mimeData: %s", mime.toLocal8Bit().data());
+    if (!m_sessionStarted) {
+        event->ignore();
+        return;
+    }
+
     if (event->mimeData()->hasFormat("text/plain") || event->mimeData()->hasFormat("text/uri-list"))
         event->acceptProposedAction();
 }
@@ -1388,6 +1393,32 @@ void MainWindow::showStatusBar(bool show)
     }
 }
 
+void MainWindow::setEnabledWidgets(bool enabled)
+{
+    m_ui->actionOpen->setEnabled(enabled);
+    m_ui->actionDownloadFromURL->setEnabled(enabled);
+    m_ui->menuEdit->setEnabled(enabled);
+    m_ui->menuView->setEnabled(enabled);
+    m_ui->menuOptions->setEnabled(enabled);
+    m_ui->menuHelp->setEnabled(enabled);
+
+    // These are reflected in the tray menu too
+    m_ui->actionUseAlternativeSpeedLimits->setEnabled(enabled);
+    m_ui->actionSetGlobalDownloadLimit->setEnabled(enabled);
+    m_ui->actionSetGlobalUploadLimit->setEnabled(enabled);
+    m_ui->actionStartAll->setEnabled(enabled);
+    m_ui->actionPauseAll->setEnabled(enabled);
+
+    m_ui->toolBar->setEnabled(enabled);
+    m_ui->centralWidget->setEnabled(enabled);
+    m_statusBar->setEnabled(enabled);
+
+    if (enabled)
+        displayRSSTab(m_ui->actionRSSReader->isChecked());
+
+    m_sessionStarted = enabled;
+}
+
 void MainWindow::loadPreferences(bool configureSession)
 {
     Logger::instance()->addMessage(tr("Options were saved successfully."));
diff --git a/src/gui/mainwindow.h b/src/gui/mainwindow.h
index ecad73c70..b423bdd35 100644
--- a/src/gui/mainwindow.h
+++ b/src/gui/mainwindow.h
@@ -103,6 +103,8 @@ public:
     void cleanup();
 
     void showNotificationBaloon(QString title, QString msg) const;
+    // After Application has handled BitTorrent::Session::startupFinished
+    void setEnabledWidgets(bool enabled);
 
 private slots:
     void balloonClicked();
@@ -261,6 +263,7 @@ private:
 #endif
     bool m_hasPython;
     QMenu *m_toolbarMenu;
+    bool m_sessionStarted;
 };
 
 #endif // MAINWINDOW_H
diff --git a/src/gui/tagfiltermodel.cpp b/src/gui/tagfiltermodel.cpp
index 5d9f81bd3..c7eed5b8a 100644
--- a/src/gui/tagfiltermodel.cpp
+++ b/src/gui/tagfiltermodel.cpp
@@ -98,6 +98,12 @@ TagFilterModel::TagFilterModel(QObject *parent)
     connect(session, &Session::tagRemoved, this, &TagFilterModel::tagRemoved);
     connect(session, &Session::torrentTagAdded, this, &TagFilterModel::torrentTagAdded);
     connect(session, &Session::torrentTagRemoved, this, &TagFilterModel::torrentTagRemoved);
+    connect(session, &Session::startupFinished, this,
+            [this, session]()
+    {
+        for (const auto &handle : session->torrents().values())
+            torrentAdded(handle);
+    });
     connect(session, &Session::torrentAdded, this, &TagFilterModel::torrentAdded);
     connect(session, &Session::torrentAboutToBeRemoved, this, &TagFilterModel::torrentAboutToBeRemoved);
     populate();
diff --git a/src/gui/torrentmodel.cpp b/src/gui/torrentmodel.cpp
index 585bc250d..828d5d55f 100644
--- a/src/gui/torrentmodel.cpp
+++ b/src/gui/torrentmodel.cpp
@@ -60,21 +60,25 @@ static bool isDarkTheme();
 TorrentModel::TorrentModel(QObject *parent)
     : QAbstractListModel(parent)
 {
-    // Load the torrents
-    using namespace BitTorrent;
-    foreach (TorrentHandle *const torrent, Session::instance()->torrents())
-        addTorrent(torrent);
-
     // Listen for torrent changes
-    connect(Session::instance(), &Session::torrentAdded, this, &TorrentModel::addTorrent);
-    connect(Session::instance(), &Session::torrentAboutToBeRemoved, this, &TorrentModel::handleTorrentAboutToBeRemoved);
-    connect(Session::instance(), &Session::torrentsUpdated, this, &TorrentModel::handleTorrentsUpdated);
-
-    connect(Session::instance(), &Session::torrentFinished, this, &TorrentModel::handleTorrentStatusUpdated);
-    connect(Session::instance(), &Session::torrentMetadataLoaded, this, &TorrentModel::handleTorrentStatusUpdated);
-    connect(Session::instance(), &Session::torrentResumed, this, &TorrentModel::handleTorrentStatusUpdated);
-    connect(Session::instance(), &Session::torrentPaused, this, &TorrentModel::handleTorrentStatusUpdated);
-    connect(Session::instance(), &Session::torrentFinishedChecking, this, &TorrentModel::handleTorrentStatusUpdated);
+    using namespace BitTorrent;
+    auto session = Session::instance();
+
+    connect(session, &Session::startupFinished, this,
+            [this, session]()
+    {
+        for (const auto &handle : session->torrents().values())
+            addTorrent(handle);
+    });
+    connect(session, &Session::torrentAdded, this, &TorrentModel::addTorrent);
+    connect(session, &Session::torrentAboutToBeRemoved, this, &TorrentModel::handleTorrentAboutToBeRemoved);
+    connect(session, &Session::torrentsUpdated, this, &TorrentModel::handleTorrentsUpdated);
+
+    connect(session, &Session::torrentFinished, this, &TorrentModel::handleTorrentStatusUpdated);
+    connect(session, &Session::torrentMetadataLoaded, this, &TorrentModel::handleTorrentStatusUpdated);
+    connect(session, &Session::torrentResumed, this, &TorrentModel::handleTorrentStatusUpdated);
+    connect(session, &Session::torrentPaused, this, &TorrentModel::handleTorrentStatusUpdated);
+    connect(session, &Session::torrentFinishedChecking, this, &TorrentModel::handleTorrentStatusUpdated);
 }
 
 int TorrentModel::rowCount(const QModelIndex &index) const
diff --git a/src/gui/transferlistfilterswidget.cpp b/src/gui/transferlistfilterswidget.cpp
index 423aa9c5b..160db32d9 100644
--- a/src/gui/transferlistfilterswidget.cpp
+++ b/src/gui/transferlistfilterswidget.cpp
@@ -94,10 +94,17 @@ FiltersBase::FiltersBase(QWidget *parent, TransferListWidget *transferList)
     connect(this, &FiltersBase::customContextMenuRequested, this, &FiltersBase::showMenu);
     connect(this, &FiltersBase::currentRowChanged, this, &FiltersBase::applyFilter);
 
-    connect(BitTorrent::Session::instance(), &BitTorrent::Session::torrentAdded
-            , this, &FiltersBase::handleNewTorrent);
-    connect(BitTorrent::Session::instance(), &BitTorrent::Session::torrentAboutToBeRemoved
-            , this, &FiltersBase::torrentAboutToBeDeleted);
+    using namespace BitTorrent;
+    auto session = Session::instance();
+
+    connect(session, &Session::startupFinished, this,
+            [this, session]()
+    {
+        for (const auto &handle : session->torrents().values())
+            handleNewTorrent(handle);
+    });
+    connect(session, &Session::torrentAdded, this, &FiltersBase::handleNewTorrent);
+    connect(session, &Session::torrentAboutToBeRemoved, this, &FiltersBase::torrentAboutToBeDeleted);
 }
 
 QSize FiltersBase::sizeHint() const
