diff --git a/app/assets/javascripts/discourse/controllers/tags-show.js.es6 b/app/assets/javascripts/discourse/controllers/tags-show.js.es6
index cac14abaa49..6170f2142b9 100644
--- a/app/assets/javascripts/discourse/controllers/tags-show.js.es6
+++ b/app/assets/javascripts/discourse/controllers/tags-show.js.es6
@@ -43,7 +43,7 @@ export default Ember.Controller.extend(BulkTopicSelection, {
   needs: ["application"],
 
   tag: null,
-  secondaryTag: null,
+  additionalTags: null,
   list: null,
   canAdminTag: Ember.computed.alias("currentUser.staff"),
   filterMode: null,
@@ -73,8 +73,8 @@ export default Ember.Controller.extend(BulkTopicSelection, {
   }.property(),
 
   showAdminControls: function() {
-    return !this.get('secondaryTag') && this.get('canAdminTag') && !this.get('category');
-  }.property('secondaryTag', 'canAdminTag', 'category'),
+    return this.get('additionalTags') && this.get('canAdminTag') && !this.get('category');
+  }.property('additionalTags', 'canAdminTag', 'category'),
 
   loadMoreTopics() {
     return this.get("list").loadMore();
diff --git a/app/assets/javascripts/discourse/routes/app-route-map.js.es6 b/app/assets/javascripts/discourse/routes/app-route-map.js.es6
index 6ce4265544f..002f998c359 100644
--- a/app/assets/javascripts/discourse/routes/app-route-map.js.es6
+++ b/app/assets/javascripts/discourse/routes/app-route-map.js.es6
@@ -132,7 +132,7 @@ export default function() {
       this.route('showCategory' + filter.capitalize(), {path: '/c/:category/:tag_id/l/' + filter});
       this.route('showParentCategory' + filter.capitalize(), {path: '/c/:parent_category/:category/:tag_id/l/' + filter});
     });
-    this.route('show', {path: 'intersection/:tag_id/:secondary_tag_id'});
+    this.route('show', {path: 'intersection/:tag_id/*additional_tags'});
   });
 
   this.resource('tagGroups', {path: '/tag_groups'}, function() {
diff --git a/app/assets/javascripts/discourse/routes/tags-show.js.es6 b/app/assets/javascripts/discourse/routes/tags-show.js.es6
index a6996544320..4fab00b9351 100644
--- a/app/assets/javascripts/discourse/routes/tags-show.js.es6
+++ b/app/assets/javascripts/discourse/routes/tags-show.js.es6
@@ -14,8 +14,11 @@ export default Discourse.Route.extend({
     var tag = this.store.createRecord("tag", { id: Handlebars.Utils.escapeExpression(params.tag_id) }),
         f = '';
 
-    if (params.secondary_tag_id) {
-      this.set("secondaryTag", this.store.createRecord("tag", { id: Handlebars.Utils.escapeExpression(params.secondary_tag_id) }));
+    if (params.additional_tags) {
+      this.set("additionalTags", _.compact(params.additional_tags.split('/')).map((tag) => {
+        return this.store.createRecord("tag", { id: Handlebars.Utils.escapeExpression(tag) });
+      }));
+      this.set("additionalTagIds", _.pluck(this.get("additionalTags"), 'id'));
     }
 
     if (params.category) {
@@ -50,7 +53,6 @@ export default Discourse.Route.extend({
     const parentCategorySlug = this.get('parentCategorySlug');
     const filter = this.get('navMode');
     const tag_id = (tag ? tag.id : 'none');
-    const secondary_tag_id = this.get('secondaryTag.id');
 
     if (categorySlug) {
       var category = Discourse.Category.findBySlug(categorySlug, parentCategorySlug);
@@ -61,8 +63,8 @@ export default Discourse.Route.extend({
       }
 
       this.set('category', category);
-    } else if (secondary_tag_id) {
-      params.filter = `tags/intersection/${tag_id}/${secondary_tag_id}`;
+    } else if (_.any(this.get("additionalTags"))) {
+      params.filter = `tags/intersection/${tag_id}/${this.get('additionalTagIds').join('/')}`;
       this.set('category', null);
     } else {
       params.filter = `tags/${tag_id}/l/${filter}`;
@@ -102,7 +104,7 @@ export default Discourse.Route.extend({
     this.controllerFor('tags.show').setProperties({
       model,
       tag: model,
-      secondaryTag: this.get('secondaryTag'),
+      additionalTags: this.get('additionalTags'),
       category: this.get('category'),
       filterMode: this.get('filterMode'),
       navMode: this.get('navMode'),
@@ -132,7 +134,7 @@ export default Discourse.Route.extend({
         // Pre-fill the tags input field
         if (controller.get('model.id')) {
           var c = self.controllerFor('composer').get('model');
-          c.set('tags', _.compact([controller.get('model.id'), controller.get('secondaryTag.id')]));
+          c.set('tags', _.flatten([controller.get('model.id')], controller.get('additionalTagIds')));
         }
       });
     },
diff --git a/app/assets/javascripts/discourse/templates/tags/show.hbs b/app/assets/javascripts/discourse/templates/tags/show.hbs
index b652898b11f..3c35139e5a6 100644
--- a/app/assets/javascripts/discourse/templates/tags/show.hbs
+++ b/app/assets/javascripts/discourse/templates/tags/show.hbs
@@ -5,7 +5,7 @@
 <div class="list-controls">
   <div class="container">
     {{#if tagNotification}}
-      {{#unless secondaryTag}}
+      {{#unless additionalTags}}
         {{tag-notifications-button action="changeTagNotification"
                                    notificationLevel=tagNotification.notification_level}}
       {{/unless}}
@@ -33,10 +33,10 @@
         {{#link-to 'tags'}}{{i18n "tagging.tags"}}{{/link-to}}
         {{fa-icon "angle-right"}}
         {{discourse-tag-bound tagRecord=tag style="simple"}}
-        {{#if secondaryTag}}
+        {{#each additionalTags as |tag|}}
           <span>&amp;</span>
-          {{discourse-tag-bound tagRecord=secondaryTag style="simple"}}
-        {{/if}}
+          {{discourse-tag-bound tagRecord=tag style="simple"}}
+        {{/each}}
       </h2>
     {{/if}}
   </div>
diff --git a/app/controllers/tags_controller.rb b/app/controllers/tags_controller.rb
index 0989f5715ea..87412084de8 100644
--- a/app/controllers/tags_controller.rb
+++ b/app/controllers/tags_controller.rb
@@ -44,7 +44,7 @@ class TagsController < ::ApplicationController
   Discourse.filters.each do |filter|
     define_method("show_#{filter}") do
       @tag_id = DiscourseTagging.clean_tag(params[:tag_id])
-      @secondary_tag_id = DiscourseTagging.clean_tag(params[:secondary_tag_id]) if params[:secondary_tag_id]
+      @additional_tags = params[:additional_tag_ids].to_s.split('/').map { |tag| DiscourseTagging.clean_tag(tag) }
 
       page = params[:page].to_i
       list_opts = build_topic_list_options
@@ -72,7 +72,7 @@ class TagsController < ::ApplicationController
       @list.more_topics_url = construct_url_with(:next, list_opts)
       @list.prev_topics_url = construct_url_with(:prev, list_opts)
       @rss = "tag"
-      @description_meta = I18n.t("rss_by_tag", tag: [@tag_id, @secondary_tag_id].compact.join(' & '))
+      @description_meta = I18n.t("rss_by_tag", tag: tag_params.join(' & '))
       @title = @description_meta
 
       canonical_url "#{Discourse.base_url_no_prefix}#{public_send(url_method(params.slice(:category, :parent_category)))}"
@@ -298,7 +298,7 @@ class TagsController < ::ApplicationController
       if params[:tag_id] == 'none'
         options[:no_tags] = true
       else
-        options[:tags] = [params[:tag_id], params[:secondary_tag_id]].compact
+        options[:tags] = tag_params
         options[:match_all_tags] = true
       end
 
@@ -317,4 +317,8 @@ class TagsController < ::ApplicationController
         raise Discourse::NotFound
       end
     end
+
+    def tag_params
+      [@tag_id].concat(Array(@additional_tags))
+    end
 end
diff --git a/config/routes.rb b/config/routes.rb
index d38ad905f42..05b39f1ed24 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -630,7 +630,7 @@ Discourse::Application.routes.draw do
       get '/:tag_id' => 'tags#show', as: 'tag_show'
       get '/c/:category/:tag_id' => 'tags#show', as: 'tag_category_show'
       get '/c/:parent_category/:category/:tag_id' => 'tags#show', as: 'tag_parent_category_category_show'
-      get '/intersection/:tag_id/:secondary_tag_id' => 'tags#show', as: 'tag_intersection'
+      get '/intersection/:tag_id/*additional_tag_ids' => 'tags#show', as: 'tag_intersection'
       get '/:tag_id/notifications' => 'tags#notifications'
       put '/:tag_id/notifications' => 'tags#update_notifications'
       put '/:tag_id' => 'tags#update'
diff --git a/lib/topic_query.rb b/lib/topic_query.rb
index 902b42c4a37..bdae2033b8b 100644
--- a/lib/topic_query.rb
+++ b/lib/topic_query.rb
@@ -464,10 +464,16 @@ class TopicQuery
 
           if @options[:match_all_tags]
             # ALL of the given tags:
+            tags_count = @options[:tags].length
             @options[:tags] = Tag.where(name: @options[:tags]).pluck(:id) unless @options[:tags][0].is_a?(Integer)
-            @options[:tags].each_with_index do |tag, index|
-              sql_alias = ['t', index].join
-              result = result.joins("INNER JOIN topic_tags #{sql_alias} ON #{sql_alias}.topic_id = topics.id AND #{sql_alias}.tag_id = #{tag}")
+
+            if tags_count == @options[:tags].length
+              @options[:tags].each_with_index do |tag, index|
+                sql_alias = ['t', index].join
+                result = result.joins("INNER JOIN topic_tags #{sql_alias} ON #{sql_alias}.topic_id = topics.id AND #{sql_alias}.tag_id = #{tag}")
+              end
+            else
+              result = result.none # don't return any results unless all tags exist in the database
             end
           else
             # ANY of the given tags:
diff --git a/spec/controllers/tags_controller_spec.rb b/spec/controllers/tags_controller_spec.rb
index fa814fef60f..cc0ad376cdd 100644
--- a/spec/controllers/tags_controller_spec.rb
+++ b/spec/controllers/tags_controller_spec.rb
@@ -4,11 +4,13 @@ describe TagsController do
   describe 'show_latest' do
     let(:tag)         { Fabricate(:tag) }
     let(:other_tag)   { Fabricate(:tag) }
+    let(:third_tag)   { Fabricate(:tag) }
     let(:category)    { Fabricate(:category) }
     let(:subcategory) { Fabricate(:category, parent_category_id: category.id) }
 
     let(:single_tag_topic) { Fabricate(:topic, tags: [tag]) }
     let(:multi_tag_topic)  { Fabricate(:topic, tags: [tag, other_tag]) }
+    let(:all_tag_topic)    { Fabricate(:topic, tags: [tag, other_tag, third_tag]) }
 
     context 'tagging disabled' do
       it "returns 404" do
@@ -27,14 +29,31 @@ describe TagsController do
         expect(response).to be_success
       end
 
-      it "can filter by multiple tags" do
-        single_tag_topic; multi_tag_topic
-        xhr :get, :show_latest, tag_id: tag.name, secondary_tag_id: other_tag.name
+      it "can filter by two tags" do
+        single_tag_topic; multi_tag_topic; all_tag_topic
+        xhr :get, :show_latest, tag_id: tag.name, additional_tag_ids: other_tag.name
         expect(response).to be_success
+        expect(assigns(:list).topics).to include all_tag_topic
         expect(assigns(:list).topics).to include multi_tag_topic
         expect(assigns(:list).topics).to_not include single_tag_topic
       end
 
+      it "can filter by multiple tags" do
+        single_tag_topic; multi_tag_topic; all_tag_topic
+        xhr :get, :show_latest, tag_id: tag.name, additional_tag_ids: "#{other_tag.name}/#{third_tag.name}"
+        expect(response).to be_success
+        expect(assigns(:list).topics).to include all_tag_topic
+        expect(assigns(:list).topics).to_not include multi_tag_topic
+        expect(assigns(:list).topics).to_not include single_tag_topic
+      end
+
+      it "does not find any tags when a tag which doesn't exist is passed" do
+        single_tag_topic
+        xhr :get, :show_latest, tag_id: tag.name, additional_tag_ids: "notatag"
+        expect(response).to be_success
+        expect(assigns(:list).topics).to_not include single_tag_topic
+      end
+
       it "can filter by category and tag" do
         xhr :get, :show_latest, tag_id: tag.name, category: category.slug
         expect(response).to be_success