diff --git a/aleksis/core/frontend/components/calendar/CalendarOverview.vue b/aleksis/core/frontend/components/calendar/CalendarOverview.vue
index f5e19bd02210c52ae14bd0067775091efaa9201a..347dd3dcafda32f781f988a6cebddf47425885e1 100644
--- a/aleksis/core/frontend/components/calendar/CalendarOverview.vue
+++ b/aleksis/core/frontend/components/calendar/CalendarOverview.vue
@@ -50,6 +50,7 @@
             <calendar-select
               v-model="selectedCalendarFeedNames"
               :calendar-feeds="calendar.calendarFeeds"
+              @input="storeActivatedCalendars"
             />
           </button-menu>
         </v-col>
@@ -92,6 +93,7 @@
               class="mb-4"
               v-model="selectedCalendarFeedNames"
               :calendar-feeds="calendar.calendarFeeds"
+              @input="storeActivatedCalendars"
             />
             <v-btn depressed block v-if="calendar" :href="calendar.allFeedsUrl">
               <v-icon left>mdi-download-outline</v-icon>
@@ -155,6 +157,7 @@ import {
 } from "aleksisAppImporter";
 
 import gqlCalendarOverview from "./calendarOverview.graphql";
+import gqlSetCalendarStatus from "./setCalendarStatus.graphql";
 
 export default {
   name: "CalendarOverview",
@@ -197,6 +200,11 @@ export default {
     calendar: {
       query: gqlCalendarOverview,
       skip: true,
+      result({ data }) {
+        this.selectedCalendarFeedNames = data.calendar.calendarFeeds
+          .filter((c) => c.activated)
+          .map((c) => c.name);
+      },
     },
   },
   computed: {
@@ -268,6 +276,15 @@ export default {
     getColorForEvent(event) {
       return event.color;
     },
+    storeActivatedCalendars() {
+      // Store currently activated calendars in the backend
+      this.$apollo.mutate({
+        mutation: gqlSetCalendarStatus,
+        variables: {
+          calendars: this.selectedCalendarFeedNames,
+        },
+      });
+    },
     fetchMoreCalendarEvents({ start, end }) {
       // Get the start and end dates of the current date range shown in the calendar
       let extendedStart = this.$refs.calendar.getStartOfWeek(start).date;
diff --git a/aleksis/core/frontend/components/calendar/calendarOverview.graphql b/aleksis/core/frontend/components/calendar/calendarOverview.graphql
index 4d55a10ad313b3561a4ec0b9a077b485d9400e23..f277ef4bbffcf9cf68532a5e1ba9ce3ecd2c813b 100644
--- a/aleksis/core/frontend/components/calendar/calendarOverview.graphql
+++ b/aleksis/core/frontend/components/calendar/calendarOverview.graphql
@@ -7,6 +7,7 @@ query ($start: Date, $end: Date) {
       description
       url
       color
+      activated
       feed {
         events(start: $start, end: $end) {
           name
diff --git a/aleksis/core/frontend/components/calendar/setCalendarStatus.graphql b/aleksis/core/frontend/components/calendar/setCalendarStatus.graphql
new file mode 100644
index 0000000000000000000000000000000000000000..633f0791c3e00f0c82886779366704086871c484
--- /dev/null
+++ b/aleksis/core/frontend/components/calendar/setCalendarStatus.graphql
@@ -0,0 +1,5 @@
+mutation ($calendars: [String]!) {
+  setCalendarStatus(calendars: $calendars) {
+    ok
+  }
+}
diff --git a/aleksis/core/mixins.py b/aleksis/core/mixins.py
index 43bed808ee3f36b98f2745a5bab329f6ece97508..d1599b6b33b553dabcb668e41e00896ba352523c 100644
--- a/aleksis/core/mixins.py
+++ b/aleksis/core/mixins.py
@@ -718,7 +718,17 @@ class CalendarEventMixin(RegistryObject):
     def value_color(cls, reference_object, request) -> str:
         return cls.get_color(request)
 
+    @classproperty
+    def valid_feed(cls):
+        """Return if the feed is valid."""
+        return cls.name != cls.__name__
+
     @classproperty
     def valid_feeds(cls):
         """Return a list of valid feeds."""
-        return [feed for feed in cls.registered_objects_list if feed.name != feed.__name__]
+        return [feed for feed in cls.registered_objects_list if feed.valid_feed]
+
+    @classproperty
+    def valid_feed_names(cls):
+        """Return a list of valid feed names."""
+        return [feed.name for feed in cls.valid_feeds]
diff --git a/aleksis/core/preferences.py b/aleksis/core/preferences.py
index 4c9758e16e3722c8775e50a11004c533366b3f05..a3be1ac89770a89c2d3ea82b64aee7adc3913c9f 100644
--- a/aleksis/core/preferences.py
+++ b/aleksis/core/preferences.py
@@ -16,7 +16,7 @@ from dynamic_preferences.types import (
 )
 from oauth2_provider.models import AbstractApplication
 
-from .mixins import PublicFilePreferenceMixin
+from .mixins import CalendarEventMixin, PublicFilePreferenceMixin
 from .models import Group, Person
 from .registries import person_preferences_registry, site_preferences_registry
 from .util.notifications import get_notification_choices_lazy
@@ -502,3 +502,18 @@ class HolidayFeedColor(StringPreference):
     verbose_name = _("Holiday calendar feed color")
     widget = ColorWidget
     required = True
+
+
+@person_preferences_registry.register
+class ActivatedCalendars(MultipleChoicePreference):
+    """Calendars that are activated for a person."""
+
+    section = calendar
+    name = "activated_calendars"
+    default = []
+    widget = SelectMultiple
+    verbose_name = _("Activated calendars")
+    required = False
+
+    field_attribute = {"initial": []}
+    choices = [(feed.name, feed.verbose_name) for feed in CalendarEventMixin.valid_feeds]
diff --git a/aleksis/core/schema/__init__.py b/aleksis/core/schema/__init__.py
index 0ce00ad587d2f43b0ed2776f9c598073c5ae401f..249f5fd7e5382923d9ec6915c3ca666b74208eef 100644
--- a/aleksis/core/schema/__init__.py
+++ b/aleksis/core/schema/__init__.py
@@ -20,7 +20,7 @@ from ..models import (
 )
 from ..util.apps import AppConfig
 from ..util.core_helpers import get_allowed_object_ids, get_app_module, get_app_packages, has_person
-from .calendar import CalendarBaseType
+from .calendar import CalendarBaseType, SetCalendarStatusMutation
 from .celery_progress import CeleryProgressFetchedMutation, CeleryProgressType
 from .custom_menu import CustomMenuType
 from .dynamic_routes import DynamicRouteType
@@ -188,6 +188,8 @@ class Mutation(graphene.ObjectType):
 
     revoke_oauth_token = OAuthRevokeTokenMutation.Field()
 
+    set_calendar_status = SetCalendarStatusMutation.Field()
+
 
 def build_global_schema():
     """Build global GraphQL schema from all apps."""
diff --git a/aleksis/core/schema/calendar.py b/aleksis/core/schema/calendar.py
index 22f8c0687d7bc6dfc626ad75d8c784b497f0b2db..6ad0f35b865d9b2fdc906ecbb494dc9827f30e45 100644
--- a/aleksis/core/schema/calendar.py
+++ b/aleksis/core/schema/calendar.py
@@ -1,11 +1,13 @@
 from datetime import datetime
 
+from django.core.exceptions import PermissionDenied
 from django.urls import reverse
 
 import graphene
 from graphene import ObjectType
 
 from aleksis.core.mixins import CalendarEventMixin
+from aleksis.core.util.core_helpers import has_person
 
 
 class CalendarEventType(ObjectType):
@@ -71,6 +73,8 @@ class CalendarType(ObjectType):
 
     url = graphene.String()
 
+    activated = graphene.Boolean()
+
     def resolve_verbose_name(root, info, **kwargs):
         return root.get_verbose_name(info.context)
 
@@ -86,6 +90,25 @@ class CalendarType(ObjectType):
     def resolve_color(root, info, **kwargs):
         return root.get_color(info.context)
 
+    def resolve_activated(root, info, **kwargs):
+        return root.name in info.context.user.person.preferences["calendar__activated_calendars"]
+
+
+class SetCalendarStatusMutation(graphene.Mutation):
+    """Mutation to change the status of a calendar."""
+
+    class Arguments:
+        calendars = graphene.List(graphene.String)
+
+    ok = graphene.Boolean()
+
+    def mutate(root, info, calendars, **kwargs):
+        if not has_person(info.context):
+            raise PermissionDenied
+        calendar_feeds = [cal for cal in calendars if cal in CalendarEventMixin.valid_feed_names]
+        info.context.user.person.preferences["calendar__activated_calendars"] = calendar_feeds
+        return SetCalendarStatusMutation(ok=True)
+
 
 class CalendarBaseType(ObjectType):
     calendar_feeds = graphene.List(CalendarType)