diff --git a/include/Cache.h b/include/Cache.h
index c141a42a3eb6b8ae38f0b7a140b444475a49c626..1f6c59f037e54554a41f4caad4826d7d0568f603 100644
--- a/include/Cache.h
+++ b/include/Cache.h
@@ -48,6 +48,9 @@ public:
         bool isFormatValid();
         void setCurrentFormat();
 
+        QByteArray image(const QString &url) const;
+        void saveImage(const QString &url, const QByteArray &data);
+
 private:
         void setNextBatchToken(lmdb::txn &txn, const QString &token);
         void insertRoomState(lmdb::txn &txn, const QString &roomid, const RoomState &state);
@@ -56,6 +59,7 @@ private:
         lmdb::dbi stateDb_;
         lmdb::dbi roomDb_;
         lmdb::dbi invitesDb_;
+        lmdb::dbi imagesDb_;
 
         bool isMounted_;
 
diff --git a/include/MatrixClient.h b/include/MatrixClient.h
index 2e76061fe5a056bebb20c2ef518da2b5708af718..2627f578be5c0a80b1464aaafea1ae4d0e18bf6e 100644
--- a/include/MatrixClient.h
+++ b/include/MatrixClient.h
@@ -98,7 +98,10 @@ signals:
         void fileUploaded(const QString &roomid, const QString &filename, const QString &url);
         void audioUploaded(const QString &roomid, const QString &filename, const QString &url);
 
-        void roomAvatarRetrieved(const QString &roomid, const QPixmap &img);
+        void roomAvatarRetrieved(const QString &roomid,
+                                 const QPixmap &img,
+                                 const QString &url,
+                                 const QByteArray &data);
         void userAvatarRetrieved(const QString &userId, const QImage &img);
         void ownAvatarRetrieved(const QPixmap &img);
         void imageDownloaded(const QString &event_id, const QPixmap &img);
diff --git a/include/RoomList.h b/include/RoomList.h
index 8487df10ae3bd300cb983d5950bfc893e6f8c74d..ed05e0bef4dce6a1956e8a525da4afb0d4632535 100644
--- a/include/RoomList.h
+++ b/include/RoomList.h
@@ -30,6 +30,7 @@
 
 class LeaveRoomDialog;
 class MatrixClient;
+class Cache;
 class OverlayModal;
 class RoomInfoListItem;
 class RoomSettings;
@@ -45,6 +46,7 @@ public:
         RoomList(QSharedPointer<MatrixClient> client, QWidget *parent = 0);
         ~RoomList();
 
+        void setCache(QSharedPointer<Cache> cache) { cache_ = cache; }
         void setInitialRooms(const QMap<QString, QSharedPointer<RoomSettings>> &settings,
                              const QMap<QString, RoomState> &states);
         void sync(const QMap<QString, RoomState> &states,
@@ -52,6 +54,7 @@ public:
         void syncInvites(const std::map<std::string, mtx::responses::InvitedRoom> &rooms);
 
         void clear();
+        void updateAvatar(const QString &room_id, const QString &url);
 
         void addRoom(const QMap<QString, QSharedPointer<RoomSettings>> &settings,
                      const RoomState &state,
@@ -64,6 +67,7 @@ signals:
         void totalUnreadMessageCountUpdated(int count);
         void acceptInvite(const QString &room_id);
         void declineInvite(const QString &room_id);
+        void roomAvatarChanged(const QString &room_id, const QPixmap &img);
 
 public slots:
         void updateRoomAvatar(const QString &roomid, const QPixmap &img);
@@ -96,4 +100,5 @@ private:
         QMap<QString, QSharedPointer<RoomInfoListItem>> rooms_;
 
         QSharedPointer<MatrixClient> client_;
+        QSharedPointer<Cache> cache_;
 };
diff --git a/src/Cache.cc b/src/Cache.cc
index 4e2f32a9d298be84ae78562f716a3a3ca188d2bf..06e45f13c10a30d9dde8f2373b759cfa6507945b 100644
--- a/src/Cache.cc
+++ b/src/Cache.cc
@@ -17,6 +17,7 @@
 
 #include <stdexcept>
 
+#include <QByteArray>
 #include <QDebug>
 #include <QFile>
 #include <QStandardPaths>
@@ -34,6 +35,7 @@ Cache::Cache(const QString &userId)
   , stateDb_{0}
   , roomDb_{0}
   , invitesDb_{0}
+  , imagesDb_{0}
   , isMounted_{false}
   , userId_{userId}
 {}
@@ -54,7 +56,7 @@ Cache::setup()
         bool isInitial = !QFile::exists(statePath);
 
         env_ = lmdb::env::create();
-        env_.set_mapsize(128UL * 1024UL * 1024UL); /* 128 MB */
+        env_.set_mapsize(256UL * 1024UL * 1024UL); /* 256 MB */
         env_.set_max_dbs(1024UL);
 
         if (isInitial) {
@@ -91,12 +93,60 @@ Cache::setup()
         stateDb_   = lmdb::dbi::open(txn, "state", MDB_CREATE);
         roomDb_    = lmdb::dbi::open(txn, "rooms", MDB_CREATE);
         invitesDb_ = lmdb::dbi::open(txn, "invites", MDB_CREATE);
+        imagesDb_  = lmdb::dbi::open(txn, "images", MDB_CREATE);
 
         txn.commit();
 
         isMounted_ = true;
 }
 
+void
+Cache::saveImage(const QString &url, const QByteArray &image)
+{
+        if (!isMounted_)
+                return;
+
+        auto key = url.toUtf8();
+
+        try {
+                auto txn = lmdb::txn::begin(env_);
+
+                lmdb::dbi_put(txn,
+                              imagesDb_,
+                              lmdb::val(key.data(), key.size()),
+                              lmdb::val(image.data(), image.size()));
+
+                txn.commit();
+        } catch (const lmdb::error &e) {
+                qCritical() << "saveImage:" << e.what();
+        }
+}
+
+QByteArray
+Cache::image(const QString &url) const
+{
+        auto key = url.toUtf8();
+
+        try {
+                auto txn = lmdb::txn::begin(env_, nullptr, MDB_RDONLY);
+
+                lmdb::val image;
+
+                bool res = lmdb::dbi_get(txn, imagesDb_, lmdb::val(key.data(), key.size()), image);
+
+                txn.commit();
+
+                if (!res)
+                        return QByteArray();
+
+                return QByteArray(image.data(), image.size());
+        } catch (const lmdb::error &e) {
+                qCritical() << "image:" << e.what();
+        }
+
+        return QByteArray();
+}
+
 void
 Cache::setState(const QString &nextBatchToken, const QMap<QString, RoomState> &states)
 {
diff --git a/src/ChatPage.cc b/src/ChatPage.cc
index a5b36d8193d708fcc56a6fbd68b98af02164ce8d..8161d62c21b0b1dcf1bbc96c28734a09b59d9164 100644
--- a/src/ChatPage.cc
+++ b/src/ChatPage.cc
@@ -232,8 +232,7 @@ ChatPage::ChatPage(QSharedPointer<MatrixClient> client, QWidget *parent)
                         view_manager_->queueAudioMessage(roomid, filename, url);
                 });
 
-        connect(
-          client_.data(), &MatrixClient::roomAvatarRetrieved, this, &ChatPage::updateTopBarAvatar);
+        connect(room_list_, &RoomList::roomAvatarChanged, this, &ChatPage::updateTopBarAvatar);
 
         connect(client_.data(),
                 &MatrixClient::initialSyncCompleted,
@@ -353,6 +352,7 @@ ChatPage::bootstrap(QString userid, QString homeserver, QString token)
         client_->getOwnProfile();
 
         cache_ = QSharedPointer<Cache>(new Cache(userid));
+        room_list_->setCache(cache_);
 
         try {
                 cache_->setup();
diff --git a/src/MatrixClient.cc b/src/MatrixClient.cc
index b5dfe514eb6444bae7c5aa4414c6cc1090447a21..1b2e020d2d84d6a165e8386ca4d2619a84ea2bca 100644
--- a/src/MatrixClient.cc
+++ b/src/MatrixClient.cc
@@ -468,7 +468,7 @@ MatrixClient::fetchRoomAvatar(const QString &roomid, const QUrl &avatar_url)
         QNetworkRequest avatar_request(endpoint);
 
         QNetworkReply *reply = get(avatar_request);
-        connect(reply, &QNetworkReply::finished, this, [this, reply, roomid]() {
+        connect(reply, &QNetworkReply::finished, this, [this, reply, roomid, avatar_url]() {
                 reply->deleteLater();
 
                 int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
@@ -486,7 +486,7 @@ MatrixClient::fetchRoomAvatar(const QString &roomid, const QUrl &avatar_url)
                 QPixmap pixmap;
                 pixmap.loadFromData(img);
 
-                emit roomAvatarRetrieved(roomid, pixmap);
+                emit roomAvatarRetrieved(roomid, pixmap, avatar_url.toString(), img);
         });
 }
 
diff --git a/src/RoomList.cc b/src/RoomList.cc
index 1e63983847406a4b07d96e081aa84d2e9e5ce246..ea13d7006de872e9d8dc7930760a4a17d214706a 100644
--- a/src/RoomList.cc
+++ b/src/RoomList.cc
@@ -15,9 +15,11 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+#include <QBuffer>
 #include <QDebug>
 #include <QObject>
 
+#include "Cache.h"
 #include "MainWindow.h"
 #include "MatrixClient.h"
 #include "OverlayModal.h"
@@ -53,9 +55,17 @@ RoomList::RoomList(QSharedPointer<MatrixClient> client, QWidget *parent)
         topLayout_->addWidget(scrollArea_);
 
         connect(client_.data(),
-                SIGNAL(roomAvatarRetrieved(const QString &, const QPixmap &)),
+                &MatrixClient::roomAvatarRetrieved,
                 this,
-                SLOT(updateRoomAvatar(const QString &, const QPixmap &)));
+                [=](const QString &room_id,
+                    const QPixmap &img,
+                    const QString &url,
+                    const QByteArray &data) {
+                        if (!cache_.isNull())
+                                cache_->saveImage(url, data);
+
+                        updateRoomAvatar(room_id, img);
+                });
 }
 
 RoomList::~RoomList() {}
@@ -79,12 +89,33 @@ RoomList::addRoom(const QMap<QString, QSharedPointer<RoomSettings>> &settings,
         rooms_.insert(room_id, QSharedPointer<RoomInfoListItem>(room_item));
 
         if (!state.getAvatar().toString().isEmpty())
-                client_->fetchRoomAvatar(room_id, state.getAvatar());
+                updateAvatar(room_id, state.getAvatar().toString());
 
         int pos = contentsLayout_->count() - 1;
         contentsLayout_->insertWidget(pos, room_item);
 }
 
+void
+RoomList::updateAvatar(const QString &room_id, const QString &url)
+{
+        if (url.isEmpty())
+                return;
+
+        QByteArray savedImgData;
+
+        if (!cache_.isNull())
+                savedImgData = cache_->image(url);
+
+        if (savedImgData.isEmpty()) {
+                client_->fetchRoomAvatar(room_id, url);
+        } else {
+                QPixmap img;
+                img.loadFromData(savedImgData);
+
+                updateRoomAvatar(room_id, img);
+        }
+}
+
 void
 RoomList::removeRoom(const QString &room_id, bool reset)
 {
@@ -194,7 +225,7 @@ RoomList::sync(const QMap<QString, RoomState> &states,
                 auto new_avatar     = state.getAvatar();
 
                 if (current_avatar != new_avatar && !new_avatar.toString().isEmpty())
-                        client_->fetchRoomAvatar(room_id, new_avatar);
+                        updateAvatar(room_id, new_avatar.toString());
 
                 room->setState(state);
         }
@@ -246,6 +277,9 @@ RoomList::updateRoomAvatar(const QString &roomid, const QPixmap &img)
         }
 
         rooms_.value(roomid)->setAvatar(img.toImage());
+
+        // Used to inform other widgets for the new image data.
+        emit roomAvatarChanged(roomid, img);
 }
 
 void
@@ -308,10 +342,7 @@ RoomList::addInvitedRoom(const QString &room_id, const mtx::responses::InvitedRo
 
         rooms_.insert(room_id, QSharedPointer<RoomInfoListItem>(room_item));
 
-        auto avatarUrl = QString::fromStdString(room.avatar());
-
-        if (!avatarUrl.isEmpty())
-                client_->fetchRoomAvatar(room_id, avatarUrl);
+        updateAvatar(room_id, QString::fromStdString(room.avatar()));
 
         int pos = contentsLayout_->count() - 1;
         contentsLayout_->insertWidget(pos, room_item);