diff --git a/app/models/badges/badge_famous_question.rb b/app/models/badges/badge_famous_question.rb
index 91c11076abbec3cc21bf07ea6375c95dc61e9a3f..bbc3633f6a088e4fdaa58199a70e5b31daf99e5e 100644
--- a/app/models/badges/badge_famous_question.rb
+++ b/app/models/badges/badge_famous_question.rb
@@ -37,7 +37,22 @@ class BadgeFamousQuestion
       notify(content, recv_user, new_user_badge)
       true
     else
-      upgrade_badge(existing_badge, post, recv_user)
+      check_upgrade(existing_badge, post, recv_user)
+    end
+  end
+
+  # @param [UserBadge] existing_badge
+  # @param [Post] post
+  # @param [User] recv_user
+  # @return
+  def self.check_upgrade(existing_badge, post, recv_user)
+    old_badge_type = UserBadge.badge_types[existing_badge.badge_type]
+    badge_type = upgrade_badge(existing_badge, post)
+    return false unless badge_type
+
+    if old_badge_type != badge_type
+      content = "Your badge has been upgraded to #{badge_type}!"
+      notify(content, recv_user, existing_badge)
     end
   end
 
@@ -45,23 +60,17 @@ class BadgeFamousQuestion
   # @param [Post] post
   # @param [User] recv_user
   # @return boolean
-  def self.upgrade_badge(user_badge, post, recv_user)
-    # Check if the badge should be turned into a golden badge
+  def self.upgrade_badge(user_badge, post)
     if post.views_count >= BADGE_AWARD_THRESHOLDS[2]
       user_badge.update(badge_type: :gold)
       return false if user_badge.errors.any?
 
-      content = 'Your badge has been upgraded to gold!'
-      notify(content, recv_user, user_badge)
-      true
-      # Check if the badge should be turned into a silver badge
+      return UserBadge.badge_types[:gold]
     elsif post.views_count >= BADGE_AWARD_THRESHOLDS[1]
       user_badge.update(badge_type: :silver)
       return false if user_badge.errors.any?
 
-      content = 'Your badge has been upgraded to silver!'
-      notify(content, recv_user, user_badge)
-      true
+      return UserBadge.badge_types[:silver]
     end
     false
   end
diff --git a/app/models/badges/badge_great_answer.rb b/app/models/badges/badge_great_answer.rb
index 3546ecf8476af3376b21e51aafe23b1e4999f858..2b278943f2531e3b9a740a9c364a8d35e6338a6f 100644
--- a/app/models/badges/badge_great_answer.rb
+++ b/app/models/badges/badge_great_answer.rb
@@ -34,7 +34,18 @@ class BadgeGreatAnswer
       notify(content, recv_user, new_user_badge)
       true
     else
-      upgrade_badge(existing_badge, post, recv_user)
+      check_upgrade(existing_badge, post, recv_user)
+    end
+  end
+
+  def self.check_upgrade(existing_badge, post, recv_user)
+    old_badge_type = UserBadge.badge_types[existing_badge.badge_type]
+    badge_type = upgrade_badge(existing_badge, post)
+    return false unless badge_type
+
+    if old_badge_type != badge_type
+      content = "Your badge has been upgraded to #{badge_type}!"
+      notify(content, recv_user, existing_badge)
     end
   end
 
@@ -42,23 +53,18 @@ class BadgeGreatAnswer
   # @param [Post] post
   # @param [User] recv_user
   # @return boolean
-  def self.upgrade_badge(user_badge, post, recv_user)
+  def self.upgrade_badge(user_badge, post)
     # Check if the badge should be turned into a golden badge
     if post.score >= BADGE_AWARD_THRESHOLDS[2]
       user_badge.update(badge_type: :gold)
       return false if user_badge.errors.any?
 
-      content = 'Your badge has been upgraded to gold!'
-      notify(content, recv_user, user_badge)
-      true
-      # Check if the badge should be turned into a silver badge
+      return UserBadge.badge_types[:gold]
     elsif post.score >= BADGE_AWARD_THRESHOLDS[1]
       user_badge.update(badge_type: :silver)
       return false if user_badge.errors.any?
 
-      content = 'Your badge has been upgraded to silver!'
-      notify(content, recv_user, user_badge)
-      true
+      return UserBadge.badge_types[:silver]
     end
     false
   end
diff --git a/app/models/badges/badge_great_question.rb b/app/models/badges/badge_great_question.rb
index d3f443760160c69c3753cb9d452be426e1f455c7..59fd6e821457060b8ec916ebbc603f94446984ee 100644
--- a/app/models/badges/badge_great_question.rb
+++ b/app/models/badges/badge_great_question.rb
@@ -35,33 +35,42 @@ class BadgeGreatQuestion
       content = "You have been awarded the badge '#{new_user_badge.badge.title}'
       for your question '#{post.title}'"
       notify(content, recv_user, new_user_badge)
-      true
     else
-      upgrade_badge(existing_badge, post, recv_user)
+      check_upgrade(existing_badge, post, recv_user)
+    end
+    true
+  end
+
+  # @param [UserBadge] existing_badge
+  # @param [Post] post
+  # @param [User] recv_user
+  # @return
+  def self.check_upgrade(existing_badge, post, recv_user)
+    old_badge_type = UserBadge.badge_types[existing_badge.badge_type]
+    badge_type = upgrade_badge(existing_badge, post)
+    return false unless badge_type
+
+    if old_badge_type != badge_type
+      content = "Your badge has been upgraded to #{badge_type}!"
+      notify(content, recv_user, existing_badge)
     end
   end
 
   # @param [UserBadge] user_badge
   # @param [Post] post
   # @param [User] recv_user
-  # @return boolean
-  def self.upgrade_badge(user_badge, post, recv_user)
-    # Check if the badge should be turned into a golden badge
+  # @return boolean OR string
+  def self.upgrade_badge(user_badge, post)
     if post.score >= BADGE_AWARD_THRESHOLDS[2]
       user_badge.update(badge_type: :gold)
       return false if user_badge.errors.any?
 
-      content = 'Your badge has been upgraded to gold!'
-      notify(content, recv_user, user_badge)
-      true
-    # Check if the badge should be turned into a silver badge
+      return UserBadge.badge_types[:gold]
     elsif post.score >= BADGE_AWARD_THRESHOLDS[1]
       user_badge.update(badge_type: :silver)
       return false if user_badge.errors.any?
 
-      content = 'Your badge has been upgraded to silver!'
-      notify(content, recv_user, user_badge)
-      true
+      return UserBadge.badge_types[:silver]
     end
     false
   end
@@ -71,8 +80,6 @@ class BadgeGreatQuestion
   def self.eligible?(post)
     post.reload
     post.question? && post.score >= BADGE_AWARD_THRESHOLDS[0]
-
-    # !recv_user.user_badges.exists?(badge_id: badge_id, badge_source: post)
   end
 
   # @param string message
diff --git a/test/fixtures/users.yml b/test/fixtures/users.yml
index e2a91b308fd54b7fc2cf4eb3c4b3eed50650ea65..fb5d54c06337990c1215171f5e47e97238c723fc 100644
--- a/test/fixtures/users.yml
+++ b/test/fixtures/users.yml
@@ -122,7 +122,7 @@ enabled_2fa:
   two_factor_token: WT65ANYXBB2SBR7III7IVWNJDS4PQF2T
   backup_2fa_code: M8lENyehyCvo9F9MbyTl1aOL
 
-<% (1..200).each do |i| %>
+<% (1..210).each do |i| %>
 user_test_<%= i %>:
   email: user_test_<%= i %>@qpixel-test.net
   encrypted_password: '$2a$11$roUHXKxecjyQ72Qn7DWs3.9eRCCoRn176kX/UNb/xiue3aGqf7xEW'
diff --git a/test/models/badges/badge_famous_question_test.rb b/test/models/badges/badge_famous_question_test.rb
index 9a2dfd6ac4b7492f90c472a6618b01d013ecba07..17112f4780409ebd66c3595604118aabc088e173 100644
--- a/test/models/badges/badge_famous_question_test.rb
+++ b/test/models/badges/badge_famous_question_test.rb
@@ -38,6 +38,22 @@ class BadgeFamousQuestionTest < ActionController::TestCase
     assert_equal @user.user_badges.where(badge_id: @badge.id, badge_source: @post).count, 0
   end
 
+  test 'user receives only one notification per badge tier' do
+    assert_equal @user.notifications.count, 2
+
+    create_views(1, BadgeFamousQuestion.badge_award_thresholds[0], @post)
+    assert_equal @user.notifications.count, 3
+
+    create_views(BadgeFamousQuestion.badge_award_thresholds[0] + 1, BadgeFamousQuestion.badge_award_thresholds[1], @post)
+    assert_equal @user.notifications.count, 4
+
+    create_views(BadgeFamousQuestion.badge_award_thresholds[1] + 1, BadgeFamousQuestion.badge_award_thresholds[2], @post)
+    assert_equal @user.notifications.count, 5
+
+    create_views(BadgeFamousQuestion.badge_award_thresholds[2] + 1, BadgeFamousQuestion.badge_award_thresholds[2] + 2, @post)
+    assert_equal @user.notifications.count, 5
+  end
+
   def create_views(start, stop, post)
     (start..stop).each do |i|
       unique_user = users("user_test_#{i}")
diff --git a/test/models/badges/badge_great_answer_test.rb b/test/models/badges/badge_great_answer_test.rb
index 02fd0bb74a81c5a622b58ec997866a74382de04c..a3a1e8f48d1f71281e1c9278eb7737c91a5239fd 100644
--- a/test/models/badges/badge_great_answer_test.rb
+++ b/test/models/badges/badge_great_answer_test.rb
@@ -51,4 +51,36 @@ class BadgeGreatAnswerTest < ActionController::TestCase
     assert_equal expected_count, post.upvote_count
     assert UserBadge.exists?(user: author, badge_id: BadgeGreatAnswer.badge_id)
   end
+
+  test 'user receives only one notification per badge tier' do
+    post = posts(:answer_one)
+    author = post.user
+    old_votes = post.upvote_count
+
+    assert_equal author.notifications.count, 2
+
+    # Create a badge (bronze, initially)
+    post.score = BadgeGreatAnswer.badge_award_thresholds[0] + 0.01
+    create_vote_and_check_badge(post, author, users(:standard_user), old_votes + 1)
+    assert_equal author.notifications.count, 3
+
+    # Create a vote and upgrade the badge to silver
+    post.score = BadgeGreatAnswer.badge_award_thresholds[1] + 0.01
+    create_vote_and_check_badge(post, author, users(:editor), old_votes + 2)
+    assert_equal author.notifications.count, 4
+
+    # Create a vote and upgrade the badge to gold
+    post.score = BadgeGreatAnswer.badge_award_thresholds[2] + 0.01
+    create_vote_and_check_badge(post, author, users(:closer), old_votes + 3)
+    assert_equal author.notifications.count, 5
+
+    # Create additional votes, for checking notifications
+    post.score = BadgeGreatAnswer.badge_award_thresholds[2] + 0.01
+    create_vote_and_check_badge(post, author, users(:standard_user), old_votes + 4)
+    post.score = BadgeGreatAnswer.badge_award_thresholds[2] + 0.01
+    create_vote_and_check_badge(post, author, users(:editor), old_votes + 5)
+    post.score = BadgeGreatAnswer.badge_award_thresholds[2] + 0.01
+    create_vote_and_check_badge(post, author, users(:closer), old_votes + 6)
+    assert_equal author.notifications.count, 5
+  end
 end
diff --git a/test/models/badges/badge_great_question_test.rb b/test/models/badges/badge_great_question_test.rb
index fe8bdbecd3c492f360060a72dde0a9871694d498..7f4b10b281803bcc722abff88fbbdf412c5d00d2 100644
--- a/test/models/badges/badge_great_question_test.rb
+++ b/test/models/badges/badge_great_question_test.rb
@@ -29,6 +29,22 @@ class BadgeGreatQuestionTest < ActionController::TestCase
     assert_equal @user.user_badges.where(badge_id: @badge.id, badge_source: @post).count, 0
   end
 
+  test 'user receives only one notification per badge tier' do
+    assert_equal @user.notifications.count, 2
+
+    create_votes(1, BRONZE_VOTES, @post)
+    assert_equal @user.notifications.count, 3
+
+    create_votes(BRONZE_VOTES + 1, SILVER_VOTES, @post)
+    assert_equal @user.notifications.count, 4
+
+    create_votes(SILVER_VOTES + 1, GOLD_VOTES, @post)
+    assert_equal @user.notifications.count, 5
+
+    create_votes(GOLD_VOTES + 1, GOLD_VOTES + 2, @post)
+    assert_equal @user.notifications.count, 5
+  end
+
   def create_votes(start, stop, post)
     (start..stop).each do |i|
       unique_user = users("user_test_#{i}")