diff --git a/CHANGELOG.md b/CHANGELOG.md
index 86d981da..32f9a2eb 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -11,6 +11,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
 ### Changed
 - Emoji autocomplete will match any part of the word and not just start, for example :drool will now helpfully suggest :blobcatdrool: and :blobcatdroolreach:
 
+### Add
+- Follow request notification support
+
 ## [2.0.2] - 2020-04-08
 ### Fixed
 - Favorite/Repeat avatars not showing up on private instances/non-public posts
diff --git a/src/components/notification/notification.js b/src/components/notification/notification.js
index e7bd769e..6deee7d5 100644
--- a/src/components/notification/notification.js
+++ b/src/components/notification/notification.js
@@ -2,6 +2,7 @@ import Status from '../status/status.vue'
 import UserAvatar from '../user_avatar/user_avatar.vue'
 import UserCard from '../user_card/user_card.vue'
 import Timeago from '../timeago/timeago.vue'
+import { isStatusNotification } from '../../services/notification_utils/notification_utils.js'
 import { highlightClass, highlightStyle } from '../../services/user_highlighter/user_highlighter.js'
 import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator'
 
@@ -32,6 +33,21 @@ const Notification = {
     },
     toggleMute () {
       this.unmuted = !this.unmuted
+    },
+    approveUser () {
+      this.$store.state.api.backendInteractor.approveUser({ id: this.user.id })
+      this.$store.dispatch('removeFollowRequest', this.user)
+      this.$store.dispatch('updateNotification', {
+        id: this.notification.id,
+        updater: notification => {
+          notification.type = 'follow'
+        }
+      })
+    },
+    denyUser () {
+      this.$store.state.api.backendInteractor.denyUser({ id: this.user.id })
+      this.$store.dispatch('removeFollowRequest', this.user)
+      this.$store.dispatch('dismissNotification', { id: this.notification.id })
     }
   },
   computed: {
@@ -57,6 +73,9 @@ const Notification = {
     },
     needMute () {
       return this.user.muted
+    },
+    isStatusNotification () {
+      return isStatusNotification(this.notification.type)
     }
   }
 }
diff --git a/src/components/notification/notification.vue b/src/components/notification/notification.vue
index 51875747..02802776 100644
--- a/src/components/notification/notification.vue
+++ b/src/components/notification/notification.vue
@@ -74,6 +74,10 @@
               <i class="fa icon-user-plus lit" />
               <small>{{ $t('notifications.followed_you') }}</small>
             </span>
+            <span v-if="notification.type === 'follow_request'">
+              <i class="fa icon-user lit" />
+              <small>{{ $t('notifications.follow_request') }}</small>
+            </span>
             <span v-if="notification.type === 'move'">
               <i class="fa icon-arrow-curved lit" />
               <small>{{ $t('notifications.migrated_to') }}</small>
@@ -87,18 +91,7 @@
             </span>
           </div>
           <div
-            v-if="notification.type === 'follow' || notification.type === 'move'"
-            class="timeago"
-          >
-            <span class="faint">
-              <Timeago
-                :time="notification.created_at"
-                :auto-update="240"
-              />
-            </span>
-          </div>
-          <div
-            v-else
+            v-if="isStatusNotification"
             class="timeago"
           >
             <router-link
@@ -112,6 +105,17 @@
               />
             </router-link>
           </div>
+          <div
+            v-else
+            class="timeago"
+          >
+            <span class="faint">
+              <Timeago
+                :time="notification.created_at"
+                :auto-update="240"
+              />
+            </span>
+          </div>
           <a
             v-if="needMute"
             href="#"
@@ -119,12 +123,30 @@
           ><i class="button-icon icon-eye-off" /></a>
         </span>
         <div
-          v-if="notification.type === 'follow'"
+          v-if="notification.type === 'follow' || notification.type === 'follow_request'"
           class="follow-text"
         >
-          <router-link :to="userProfileLink">
+          <router-link
+            :to="userProfileLink"
+            class="follow-name"
+          >
             @{{ notification.from_profile.screen_name }}
           </router-link>
+          <div
+            v-if="notification.type === 'follow_request'"
+            style="white-space: nowrap;"
+          >
+            <i
+              class="icon-ok button-icon add-reaction-button"
+              :title="$t('tool_tip.accept_follow_request')"
+              @click="approveUser()"
+            />
+            <i
+              class="icon-cancel button-icon add-reaction-button"
+              :title="$t('tool_tip.accept_follow_request')"
+              @click="denyUser()"
+            />
+          </div>
         </div>
         <div
           v-else-if="notification.type === 'move'"
diff --git a/src/components/notifications/notifications.scss b/src/components/notifications/notifications.scss
index a8f4430f..80dad28b 100644
--- a/src/components/notifications/notifications.scss
+++ b/src/components/notifications/notifications.scss
@@ -82,6 +82,16 @@
   .follow-text, .move-text {
     padding: 0.5em 0;
     overflow-wrap: break-word;
+    display: flex;
+    justify-content: space-between;
+
+    .follow-name {
+      display: block;
+      max-width: 100%;
+      overflow: hidden;
+      text-overflow: ellipsis;
+      white-space: nowrap;
+    }
   }
 
   .status-el {
@@ -143,6 +153,11 @@
       color: var(--cGreen, $fallback--cGreen);
     }
 
+    .icon-user.lit {
+      color: $fallback--cBlue;
+      color: var(--cBlue, $fallback--cBlue);
+    }
+
     .icon-user-plus.lit {
       color: $fallback--cBlue;
       color: var(--cBlue, $fallback--cBlue);
diff --git a/src/i18n/en.json b/src/i18n/en.json
index 54d0608e..37d9591c 100644
--- a/src/i18n/en.json
+++ b/src/i18n/en.json
@@ -124,6 +124,7 @@
     "broken_favorite": "Unknown status, searching for it...",
     "favorited_you": "favorited your status",
     "followed_you": "followed you",
+    "follow_request": "wants to follow you",
     "load_older": "Load older notifications",
     "notifications": "Notifications",
     "read": "Read!",
@@ -697,7 +698,9 @@
     "reply": "Reply",
     "favorite": "Favorite",
     "add_reaction": "Add Reaction",
-    "user_settings": "User Settings"
+    "user_settings": "User Settings",
+    "accept_follow_request": "Accept follow request",
+    "reject_follow_request": "Reject follow request"
   },
   "upload":{
     "error": {
diff --git a/src/modules/config.js b/src/modules/config.js
index 7997521d..8f4638f5 100644
--- a/src/modules/config.js
+++ b/src/modules/config.js
@@ -34,7 +34,8 @@ export const defaultState = {
     likes: true,
     repeats: true,
     moves: true,
-    emojiReactions: false
+    emojiReactions: false,
+    followRequest: true
   },
   webPushNotifications: false,
   muteWords: [],
diff --git a/src/modules/statuses.js b/src/modules/statuses.js
index f1b7dcbd..239f41eb 100644
--- a/src/modules/statuses.js
+++ b/src/modules/statuses.js
@@ -13,6 +13,7 @@ import {
   omitBy
 } from 'lodash'
 import { set } from 'vue'
+import { isStatusNotification } from '../services/notification_utils/notification_utils.js'
 import apiService from '../services/api/api.service.js'
 // import parse from '../services/status_parser/status_parser.js'
 
@@ -321,7 +322,7 @@ const addNewStatuses = (state, { statuses, showImmediately = false, timeline, us
 
 const addNewNotifications = (state, { dispatch, notifications, older, visibleNotificationTypes, rootGetters }) => {
   each(notifications, (notification) => {
-    if (notification.type !== 'follow' && notification.type !== 'move') {
+    if (isStatusNotification(notification.type)) {
       notification.action = addStatusToGlobalStorage(state, notification.action).item
       notification.status = notification.status && addStatusToGlobalStorage(state, notification.status).item
     }
@@ -361,13 +362,16 @@ const addNewNotifications = (state, { dispatch, notifications, older, visibleNot
           case 'move':
             i18nString = 'migrated_to'
             break
+          case 'follow_request':
+            i18nString = 'follow_request'
+            break
         }
 
         if (notification.type === 'pleroma:emoji_reaction') {
           notifObj.body = rootGetters.i18n.t('notifications.reacted_with', [notification.emoji])
         } else if (i18nString) {
           notifObj.body = rootGetters.i18n.t('notifications.' + i18nString)
-        } else {
+        } else if (isStatusNotification(notification.type)) {
           notifObj.body = notification.status.text
         }
 
@@ -521,6 +525,13 @@ export const mutations = {
       notification.seen = true
     })
   },
+  dismissNotification (state, { id }) {
+    state.notifications.data = state.notifications.data.filter(n => n.id !== id)
+  },
+  updateNotification (state, { id, updater }) {
+    const notification = find(state.notifications.data, n => n.id === id)
+    notification && updater(notification)
+  },
   queueFlush (state, { timeline, id }) {
     state.timelines[timeline].flushMarker = id
   },
@@ -680,6 +691,13 @@ const statuses = {
         credentials: rootState.users.currentUser.credentials
       })
     },
+    dismissNotification ({ rootState, commit }, { id }) {
+      rootState.api.backendInteractor.dismissNotification({ id })
+        .then(() => commit('dismissNotification', { id }))
+    },
+    updateNotification ({ rootState, commit }, { id, updater }) {
+      commit('updateNotification', { id, updater })
+    },
     fetchFavsAndRepeats ({ rootState, commit }, id) {
       Promise.all([
         rootState.api.backendInteractor.fetchFavoritedByUsers({ id }),
diff --git a/src/services/api/api.service.js b/src/services/api/api.service.js
index 3c6b8f4e..3a58c38d 100644
--- a/src/services/api/api.service.js
+++ b/src/services/api/api.service.js
@@ -29,6 +29,7 @@ const MASTODON_LOGIN_URL = '/api/v1/accounts/verify_credentials'
 const MASTODON_REGISTRATION_URL = '/api/v1/accounts'
 const MASTODON_USER_FAVORITES_TIMELINE_URL = '/api/v1/favourites'
 const MASTODON_USER_NOTIFICATIONS_URL = '/api/v1/notifications'
+const MASTODON_DISMISS_NOTIFICATION_URL = id => `/api/v1/notifications/${id}/dismiss`
 const MASTODON_FAVORITE_URL = id => `/api/v1/statuses/${id}/favourite`
 const MASTODON_UNFAVORITE_URL = id => `/api/v1/statuses/${id}/unfavourite`
 const MASTODON_RETWEET_URL = id => `/api/v1/statuses/${id}/reblog`
@@ -1006,6 +1007,15 @@ const unmuteDomain = ({ domain, credentials }) => {
   })
 }
 
+const dismissNotification = ({ credentials, id }) => {
+  return promisedRequest({
+    url: MASTODON_DISMISS_NOTIFICATION_URL(id),
+    method: 'POST',
+    payload: { id },
+    credentials
+  })
+}
+
 export const getMastodonSocketURI = ({ credentials, stream, args = {} }) => {
   return Object.entries({
     ...(credentials
@@ -1161,6 +1171,7 @@ const apiService = {
   denyUser,
   suggestions,
   markNotificationsAsSeen,
+  dismissNotification,
   vote,
   fetchPoll,
   fetchFavoritedByUsers,
diff --git a/src/services/entity_normalizer/entity_normalizer.service.js b/src/services/entity_normalizer/entity_normalizer.service.js
index 84169a7b..6cacd0b8 100644
--- a/src/services/entity_normalizer/entity_normalizer.service.js
+++ b/src/services/entity_normalizer/entity_normalizer.service.js
@@ -1,4 +1,5 @@
 import escape from 'escape-html'
+import { isStatusNotification } from '../notification_utils/notification_utils.js'
 
 const qvitterStatusType = (status) => {
   if (status.is_post_verb) {
@@ -346,9 +347,7 @@ export const parseNotification = (data) => {
   if (masto) {
     output.type = mastoDict[data.type] || data.type
     output.seen = data.pleroma.is_seen
-    output.status = output.type === 'follow' || output.type === 'move'
-      ? null
-      : parseStatus(data.status)
+    output.status = isStatusNotification(output.type) ? parseStatus(data.status) : null
     output.action = output.status // TODO: Refactor, this is unneeded
     output.target = output.type !== 'move'
       ? null
diff --git a/src/services/notification_utils/notification_utils.js b/src/services/notification_utils/notification_utils.js
index b17bd7bf..eb479227 100644
--- a/src/services/notification_utils/notification_utils.js
+++ b/src/services/notification_utils/notification_utils.js
@@ -1,4 +1,4 @@
-import { filter, sortBy } from 'lodash'
+import { filter, sortBy, includes } from 'lodash'
 
 export const notificationsFromStore = store => store.state.statuses.notifications.data
 
@@ -7,10 +7,15 @@ export const visibleTypes = store => ([
   store.state.config.notificationVisibility.mentions && 'mention',
   store.state.config.notificationVisibility.repeats && 'repeat',
   store.state.config.notificationVisibility.follows && 'follow',
+  store.state.config.notificationVisibility.followRequest && 'follow_request',
   store.state.config.notificationVisibility.moves && 'move',
   store.state.config.notificationVisibility.emojiReactions && 'pleroma:emoji_reaction'
 ].filter(_ => _))
 
+const statusNotifications = ['like', 'mention', 'repeat', 'pleroma:emoji_reaction']
+
+export const isStatusNotification = (type) => includes(statusNotifications, type)
+
 const sortById = (a, b) => {
   const seqA = Number(a.id)
   const seqB = Number(b.id)
diff --git a/static/fontello.json b/static/fontello.json
index 5a7086a2..5963b68b 100755
--- a/static/fontello.json
+++ b/static/fontello.json
@@ -345,6 +345,18 @@
       "css": "link",
       "code": 59427,
       "src": "fontawesome"
+    },
+    {
+      "uid": "8b80d36d4ef43889db10bc1f0dc9a862",
+      "css": "user",
+      "code": 59428,
+      "src": "fontawesome"
+    },
+    {
+      "uid": "12f4ece88e46abd864e40b35e05b11cd",
+      "css": "ok",
+      "code": 59431,
+      "src": "fontawesome"
     }
   ]
-}
+}
\ No newline at end of file