diff --git a/Telegram/SourceFiles/auth_session.cpp b/Telegram/SourceFiles/auth_session.cpp
index 1a18fb5f6..1eb8bb80a 100644
--- a/Telegram/SourceFiles/auth_session.cpp
+++ b/Telegram/SourceFiles/auth_session.cpp
@@ -83,6 +83,7 @@ QByteArray AuthSessionSettings::serialize() const {
 		stream << qint32(_variables.supportSwitch);
 		stream << qint32(_variables.supportFixChatsOrder ? 1 : 0);
 		stream << qint32(_variables.supportTemplatesAutocomplete ? 1 : 0);
+		stream << qint32(_variables.supportChatsTimeSlice.current());
 	}
 	return result;
 }
@@ -113,6 +114,7 @@ void AuthSessionSettings::constructFromSerialized(const QByteArray &serialized)
 	qint32 supportSwitch = static_cast<qint32>(_variables.supportSwitch);
 	qint32 supportFixChatsOrder = _variables.supportFixChatsOrder ? 1 : 0;
 	qint32 supportTemplatesAutocomplete = _variables.supportTemplatesAutocomplete ? 1 : 0;
+	qint32 supportChatsTimeSlice = _variables.supportChatsTimeSlice.current();
 
 	stream >> selectorTab;
 	stream >> lastSeenWarningSeen;
@@ -176,6 +178,9 @@ void AuthSessionSettings::constructFromSerialized(const QByteArray &serialized)
 	if (!stream.atEnd()) {
 		stream >> supportTemplatesAutocomplete;
 	}
+	if (!stream.atEnd()) {
+		stream >> supportChatsTimeSlice;
+	}
 	if (stream.status() != QDataStream::Ok) {
 		LOG(("App Error: "
 			"Bad data for AuthSessionSettings::constructFromSerialized()"));
@@ -243,6 +248,19 @@ void AuthSessionSettings::constructFromSerialized(const QByteArray &serialized)
 	}
 	_variables.supportFixChatsOrder = (supportFixChatsOrder == 1);
 	_variables.supportTemplatesAutocomplete = (supportTemplatesAutocomplete == 1);
+	_variables.supportChatsTimeSlice = supportChatsTimeSlice;
+}
+
+void AuthSessionSettings::setSupportChatsTimeSlice(int slice) {
+	_variables.supportChatsTimeSlice = slice;
+}
+
+int AuthSessionSettings::supportChatsTimeSlice() const {
+	return _variables.supportChatsTimeSlice.current();
+}
+
+rpl::producer<int> AuthSessionSettings::supportChatsTimeSliceValue() const {
+	return _variables.supportChatsTimeSlice.value();
 }
 
 void AuthSessionSettings::setTabbedSelectorSectionEnabled(bool enabled) {
diff --git a/Telegram/SourceFiles/auth_session.h b/Telegram/SourceFiles/auth_session.h
index 8775453bf..a63bed5db 100644
--- a/Telegram/SourceFiles/auth_session.h
+++ b/Telegram/SourceFiles/auth_session.h
@@ -102,6 +102,9 @@ public:
 	bool supportTemplatesAutocomplete() const {
 		return _variables.supportTemplatesAutocomplete;
 	}
+	void setSupportChatsTimeSlice(int slice);
+	int supportChatsTimeSlice() const;
+	rpl::producer<int> supportChatsTimeSliceValue() const;
 
 	ChatHelpers::SelectorTab selectorTab() const {
 		return _variables.selectorTab;
@@ -220,9 +223,14 @@ private:
 			= Calls::PeerToPeer();
 		Ui::InputSubmitSettings sendSubmitWay;
 
+		static constexpr auto kDefaultSupportChatsLimitSlice
+			= 30 * 24 * 60 * 60;
+
 		Support::SwitchSettings supportSwitch;
 		bool supportFixChatsOrder = true;
 		bool supportTemplatesAutocomplete = true;
+		rpl::variable<int> supportChatsTimeSlice
+			= kDefaultSupportChatsLimitSlice;
 	};
 
 	rpl::event_stream<bool> _thirdSectionInfoEnabledValue;
diff --git a/Telegram/SourceFiles/dialogs/dialogs.style b/Telegram/SourceFiles/dialogs/dialogs.style
index 1922f5cad..4071006da 100644
--- a/Telegram/SourceFiles/dialogs/dialogs.style
+++ b/Telegram/SourceFiles/dialogs/dialogs.style
@@ -194,10 +194,28 @@ dialogsUpdateButton: FlatButton {
 		color: activeButtonBgRipple;
 	}
 }
-
 dialogsInstallUpdate: icon {{ "install_update", activeButtonFg }};
 dialogsInstallUpdateOver: icon {{ "install_update", activeButtonFgOver }};
 
+dialogsLoadMoreButton: FlatButton(dialogsUpdateButton) {
+	color: lightButtonFg;
+	overColor: lightButtonFg;
+	bgColor: lightButtonBg;
+	overBgColor: lightButtonBgOver;
+	ripple: RippleAnimation(defaultRippleAnimation) {
+		color: lightButtonBgRipple;
+	}
+
+	height: 36px;
+	textTop: 9px;
+}
+dialogsLoadMore: icon {{ "install_update-flip_vertical", lightButtonFg }};
+dialogsLoadMoreLoading: InfiniteRadialAnimation(defaultInfiniteRadialAnimation) {
+	color: lightButtonFg;
+	thickness: 3px;
+	size: size(12px, 12px);
+}
+
 dialogsForwardHeight: 32px;
 dialogsForwardTextLeft: 35px;
 dialogsForwardTextTop: 6px;
diff --git a/Telegram/SourceFiles/dialogs/dialogs_widget.cpp b/Telegram/SourceFiles/dialogs/dialogs_widget.cpp
index f1b460c05..75793db82 100644
--- a/Telegram/SourceFiles/dialogs/dialogs_widget.cpp
+++ b/Telegram/SourceFiles/dialogs/dialogs_widget.cpp
@@ -16,6 +16,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 #include "ui/widgets/buttons.h"
 #include "ui/widgets/input_fields.h"
 #include "ui/wrap/fade_wrap.h"
+#include "ui/effects/radial_animation.h"
 #include "lang/lang_keys.h"
 #include "application.h"
 #include "mainwindow.h"
@@ -43,9 +44,16 @@ QString SwitchToChooseFromQuery() {
 
 } // namespace
 
-class DialogsWidget::UpdateButton : public Ui::RippleButton {
+class DialogsWidget::BottomButton : public Ui::RippleButton {
 public:
-	UpdateButton(QWidget *parent);
+	BottomButton(
+		QWidget *parent,
+		const QString &text,
+		const style::FlatButton &st,
+		const style::icon &icon,
+		const style::icon &iconOver);
+
+	void setText(const QString &text);
 
 protected:
 	void paintEvent(QPaintEvent *e) override;
@@ -53,39 +61,84 @@ protected:
 	void onStateChanged(State was, StateChangeSource source) override;
 
 private:
+	void step_radial(TimeMs ms, bool timer);
+
 	QString _text;
 	const style::FlatButton &_st;
+	const style::icon &_icon;
+	const style::icon &_iconOver;
+	std::unique_ptr<Ui::InfiniteRadialAnimation> _loading;
 
 };
 
-DialogsWidget::UpdateButton::UpdateButton(QWidget *parent) : RippleButton(parent, st::dialogsUpdateButton.ripple)
-, _text(lang(lng_update_telegram).toUpper())
-, _st(st::dialogsUpdateButton) {
+DialogsWidget::BottomButton::BottomButton(
+	QWidget *parent,
+	const QString &text,
+	const style::FlatButton &st,
+	const style::icon &icon,
+	const style::icon &iconOver)
+: RippleButton(parent, st.ripple)
+, _text(text.toUpper())
+, _st(st)
+, _icon(icon)
+, _iconOver(iconOver) {
 	resize(st::columnMinimalWidthLeft, _st.height);
 }
 
-void DialogsWidget::UpdateButton::onStateChanged(State was, StateChangeSource source) {
-	RippleButton::onStateChanged(was, source);
+void DialogsWidget::BottomButton::setText(const QString &text) {
+	_text = text.toUpper();
 	update();
 }
 
-void DialogsWidget::UpdateButton::paintEvent(QPaintEvent *e) {
-	QPainter p(this);
+void DialogsWidget::BottomButton::step_radial(TimeMs ms, bool timer) {
+	if (timer && !anim::Disabled() && width() < st::columnMinimalWidthLeft) {
+		update();
+	}
+}
+
+void DialogsWidget::BottomButton::onStateChanged(State was, StateChangeSource source) {
+	RippleButton::onStateChanged(was, source);
+	if ((was & StateFlag::Disabled) != (state() & StateFlag::Disabled)) {
+		_loading = isDisabled()
+			? std::make_unique<Ui::InfiniteRadialAnimation>(
+				animation(this, &BottomButton::step_radial),
+				st::dialogsLoadMoreLoading)
+			: nullptr;
+		if (_loading) {
+			_loading->start();
+		}
+	}
+	update();
+}
+
+void DialogsWidget::BottomButton::paintEvent(QPaintEvent *e) {
+	Painter p(this);
+
+	const auto over = isOver() && !isDisabled();
 
 	QRect r(0, height() - _st.height, width(), _st.height);
-	p.fillRect(r, isOver() ? _st.overBgColor : _st.bgColor);
+	p.fillRect(r, over ? _st.overBgColor : _st.bgColor);
 
-	paintRipple(p, 0, 0, getms());
+	if (!isDisabled()) {
+		paintRipple(p, 0, 0, getms());
+	}
 
-	p.setFont(isOver() ? _st.overFont : _st.font);
+	p.setFont(over ? _st.overFont : _st.font);
 	p.setRenderHint(QPainter::TextAntialiasing);
-	p.setPen(isOver() ? _st.overColor : _st.color);
+	p.setPen(over ? _st.overColor : _st.color);
 
 	if (width() >= st::columnMinimalWidthLeft) {
 		r.setTop(_st.textTop);
 		p.drawText(r, _text, style::al_top);
+	} else if (isDisabled() && _loading) {
+		_loading->draw(
+			p,
+			QPoint(
+				(width() - st::dialogsLoadMoreLoading.size.width()) / 2,
+				(height() - st::dialogsLoadMoreLoading.size.height()) / 2),
+			width());
 	} else {
-		(isOver() ? st::dialogsInstallUpdateOver : st::dialogsInstallUpdate).paintInCenter(p, r);
+		(over ? _iconOver : _icon).paintInCenter(p, r);
 	}
 }
 
@@ -173,6 +226,7 @@ DialogsWidget::DialogsWidget(QWidget *parent, not_null<Window::Controller*> cont
 	updateJumpToDateVisibility(true);
 	updateSearchFromVisibility(true);
 	setupConnectingWidget();
+	setupSupportLoadingLimit();
 }
 
 void DialogsWidget::setupConnectingWidget() {
@@ -181,13 +235,29 @@ void DialogsWidget::setupConnectingWidget() {
 		Window::AdaptiveIsOneColumn());
 }
 
+void DialogsWidget::setupSupportLoadingLimit() {
+	if (!Auth().supportMode()) {
+		return;
+	}
+	Auth().settings().supportChatsTimeSliceValue(
+	) | rpl::start_with_next([=](int seconds) {
+		_dialogsLoadTill = seconds ? std::max(unixtime() - seconds, 0) : 0;
+		refreshLoadMoreButton();
+	}, lifetime());
+}
+
 void DialogsWidget::checkUpdateStatus() {
 	Expects(!Core::UpdaterDisabled());
 
 	using Checker = Core::UpdateChecker;
 	if (Checker().state() == Checker::State::Ready) {
 		if (_updateTelegram) return;
-		_updateTelegram.create(this);
+		_updateTelegram.create(
+			this,
+			lang(lng_update_telegram),
+			st::dialogsUpdateButton,
+			st::dialogsInstallUpdate,
+			st::dialogsInstallUpdateOver);
 		_updateTelegram->show();
 		_updateTelegram->setClickedCallback([] {
 			Core::checkReadyUpdate();
@@ -369,6 +439,10 @@ void DialogsWidget::dialogsReceived(
 	_dialogsRequestId = 0;
 	loadDialogs();
 
+	if (!_dialogsRequestId) {
+		refreshLoadMoreButton();
+	}
+
 	Auth().data().moreChatsLoaded().notify();
 	if (_dialogsFull && _pinnedDialogsReceived) {
 		Auth().data().allChatsLoaded().set(true);
@@ -425,6 +499,36 @@ void DialogsWidget::updateDialogsOffset(
 	}
 }
 
+void DialogsWidget::refreshLoadMoreButton() {
+	if (_dialogsFull || !_dialogsLoadTill) {
+		_loadMoreChats.destroy();
+		updateControlsGeometry();
+		return;
+	}
+	if (!_loadMoreChats) {
+		_loadMoreChats.create(
+			this,
+			"Load more",
+			st::dialogsLoadMoreButton,
+			st::dialogsLoadMore,
+			st::dialogsLoadMore);
+		_loadMoreChats->addClickHandler([=] {
+			if (_loadMoreChats->isDisabled()) {
+				return;
+			}
+			const auto max = Auth().settings().supportChatsTimeSlice();
+			_dialogsLoadTill = _dialogsOffsetDate
+				? (_dialogsOffsetDate - max)
+				: (unixtime() - max);
+			loadDialogs();
+		});
+		updateControlsGeometry();
+	}
+	const auto loading = !loadingBlockedByDate();
+	_loadMoreChats->setDisabled(loading);
+	_loadMoreChats->setText(loading ? "Loading..." : "Load more");
+}
+
 void DialogsWidget::pinnedDialogsReceived(
 		const MTPmessages_PeerDialogs &result,
 		mtpRequestId requestId) {
@@ -731,11 +835,21 @@ void DialogsWidget::onSearchMore() {
 	}
 }
 
+bool DialogsWidget::loadingBlockedByDate() const {
+	return !_dialogsFull
+		&& !_dialogsRequestId
+		&& (_dialogsLoadTill > 0)
+		&& (_dialogsOffsetDate > 0)
+		&& (_dialogsOffsetDate <= _dialogsLoadTill);
+}
+
 void DialogsWidget::loadDialogs() {
 	if (_dialogsRequestId) return;
 	if (_dialogsFull) {
 		_inner->addAllSavedPeers();
 		return;
+	} else if (loadingBlockedByDate()) {
+		return;
 	}
 
 	const auto firstLoad = !_dialogsOffsetDate;
@@ -759,6 +873,7 @@ void DialogsWidget::loadDialogs() {
 	if (!_pinnedDialogsReceived) {
 		loadPinnedDialogs();
 	}
+	refreshLoadMoreButton();
 }
 
 void DialogsWidget::loadPinnedDialogs() {
@@ -1205,11 +1320,19 @@ void DialogsWidget::updateControlsGeometry() {
 	auto addToScroll = App::main() ? App::main()->contentScrollAddToY() : 0;
 	auto newScrollTop = _scroll->scrollTop() + addToScroll;
 	auto scrollHeight = height() - scrollTop;
-	if (_updateTelegram) {
-		auto updateHeight = _updateTelegram->height();
-		_updateTelegram->setGeometry(0, height() - updateHeight, width(), updateHeight);
-		scrollHeight -= updateHeight;
-	}
+	const auto putBottomButton = [&](object_ptr<BottomButton> &button) {
+		if (button) {
+			const auto buttonHeight = button->height();
+			scrollHeight -= buttonHeight;
+			button->setGeometry(
+				0,
+				scrollTop + scrollHeight,
+				width(),
+				buttonHeight);
+		}
+	};
+	putBottomButton(_updateTelegram);
+	putBottomButton(_loadMoreChats);
 	auto wasScrollHeight = _scroll->height();
 	_scroll->setGeometry(0, scrollTop, width(), scrollHeight);
 	if (scrollHeight != wasScrollHeight) {
diff --git a/Telegram/SourceFiles/dialogs/dialogs_widget.h b/Telegram/SourceFiles/dialogs/dialogs_widget.h
index 14dde02b1..6a77a5ff6 100644
--- a/Telegram/SourceFiles/dialogs/dialogs_widget.h
+++ b/Telegram/SourceFiles/dialogs/dialogs_widget.h
@@ -152,6 +152,7 @@ private:
 		const QVector<MTPDialog> &dialogs,
 		const QVector<MTPMessage> &messages);
 
+	void setupSupportLoadingLimit();
 	void setupConnectingWidget();
 	bool searchForPeersRequired(const QString &query) const;
 	void setSearchInChat(Dialogs::Key chat, UserData *from = nullptr);
@@ -166,6 +167,9 @@ private:
 	void updateForwardBar();
 	void checkUpdateStatus();
 
+	bool loadingBlockedByDate() const;
+	void refreshLoadMoreButton();
+
 	bool dialogsFailed(const RPCError &error, mtpRequestId req);
 	bool searchFailed(DialogsSearchRequestType type, const RPCError &error, mtpRequestId req);
 	bool peopleFailed(const RPCError &error, mtpRequestId req);
@@ -175,7 +179,8 @@ private:
 	QTimer _chooseByDragTimer;
 
 	bool _dialogsFull = false;
-	int32 _dialogsOffsetDate = 0;
+	TimeId _dialogsLoadTill = 0;
+	TimeId _dialogsOffsetDate = 0;
 	MsgId _dialogsOffsetId = 0;
 	PeerData *_dialogsOffsetPeer = nullptr;
 	mtpRequestId _dialogsRequestId = 0;
@@ -191,8 +196,9 @@ private:
 	object_ptr<Ui::IconButton> _lockUnlock;
 	object_ptr<Ui::ScrollArea> _scroll;
 	QPointer<DialogsInner> _inner;
-	class UpdateButton;
-	object_ptr<UpdateButton> _updateTelegram = { nullptr };
+	class BottomButton;
+	object_ptr<BottomButton> _updateTelegram = { nullptr };
+	object_ptr<BottomButton> _loadMoreChats = { nullptr };
 	base::unique_qptr<Window::ConnectingWidget> _connecting;
 
 	Animation _a_show;
diff --git a/Telegram/SourceFiles/settings/settings_chat.cpp b/Telegram/SourceFiles/settings/settings_chat.cpp
index 8b1ce0619..d5946c445 100644
--- a/Telegram/SourceFiles/settings/settings_chat.cpp
+++ b/Telegram/SourceFiles/settings/settings_chat.cpp
@@ -908,30 +908,14 @@ void SetupThemeOptions(not_null<Ui::VerticalLayout*> container) {
 	AddSkip(container);
 }
 
-void SetupSupport(not_null<Ui::VerticalLayout*> container) {
-	AddSkip(container);
-
-	AddSubsectionTitle(container, rpl::single(qsl("Support settings")));
-
-	AddSkip(container, st::settingsSendTypeSkip);
-
+void SetupSupportSwitchSettings(not_null<Ui::VerticalLayout*> container) {
 	using SwitchType = Support::SwitchSettings;
-
-	const auto skip = st::settingsSendTypeSkip;
-	auto wrap = object_ptr<Ui::VerticalLayout>(container);
-	const auto inner = wrap.data();
-	container->add(
-		object_ptr<Ui::OverrideMargins>(
-			container,
-			std::move(wrap),
-			QMargins(0, skip, 0, skip)));
-
 	const auto group = std::make_shared<Ui::RadioenumGroup<SwitchType>>(
 		Auth().settings().supportSwitch());
 	const auto add = [&](SwitchType value, const QString &label) {
-		inner->add(
+		container->add(
 			object_ptr<Ui::Radioenum<SwitchType>>(
-				inner,
+				container,
 				group,
 				value,
 				label,
@@ -945,6 +929,62 @@ void SetupSupport(not_null<Ui::VerticalLayout*> container) {
 		Auth().settings().setSupportSwitch(value);
 		Local::writeUserSettings();
 	});
+}
+
+void SetupSupportChatsLimitSlice(not_null<Ui::VerticalLayout*> container) {
+	constexpr auto kDayDuration = 24 * 60 * 60;
+	struct Option {
+		int days = 0;
+		QString label;
+	};
+	const auto options = std::vector<Option>{
+		{ 1, "1 day" },
+		{ 7, "1 week" },
+		{ 30, "1 month" },
+		{ 365, "1 year" },
+		{ 0, "All of them" },
+	};
+	const auto current = Auth().settings().supportChatsTimeSlice();
+	const auto days = current / kDayDuration;
+	const auto best = ranges::min_element(
+		options,
+		std::less<>(),
+		[&](const Option &option) { return std::abs(option.days - days); });
+
+	const auto group = std::make_shared<Ui::RadiobuttonGroup>(best->days);
+	for (const auto &option : options) {
+		container->add(
+			object_ptr<Ui::Radiobutton>(
+				container,
+				group,
+				option.days,
+				option.label,
+				st::settingsSendType),
+			st::settingsSendTypePadding);
+	}
+	group->setChangedCallback([=](int days) {
+		Auth().settings().setSupportChatsTimeSlice(days * kDayDuration);
+		Local::writeUserSettings();
+	});
+}
+
+void SetupSupport(not_null<Ui::VerticalLayout*> container) {
+	AddSkip(container);
+
+	AddSubsectionTitle(container, rpl::single(qsl("Support settings")));
+
+	AddSkip(container, st::settingsSendTypeSkip);
+
+	const auto skip = st::settingsSendTypeSkip;
+	auto wrap = object_ptr<Ui::VerticalLayout>(container);
+	const auto inner = wrap.data();
+	container->add(
+		object_ptr<Ui::OverrideMargins>(
+			container,
+			std::move(wrap),
+			QMargins(0, skip, 0, skip)));
+
+	SetupSupportSwitchSettings(inner);
 
 	AddSkip(inner, st::settingsCheckboxesSkip);
 
@@ -963,6 +1003,13 @@ void SetupSupport(not_null<Ui::VerticalLayout*> container) {
 	}, inner->lifetime());
 
 	AddSkip(inner, st::settingsCheckboxesSkip);
+
+	AddSubsectionTitle(inner, rpl::single(qsl("Load chats for a period")));
+
+	SetupSupportChatsLimitSlice(inner);
+
+	AddSkip(inner, st::settingsCheckboxesSkip);
+
 	AddSkip(inner);
 }