diff --git a/config.sample.yaml b/config.sample.yaml
index 86282651d6783991986434681a83eb8f154cf2c7..19e2897938b27bd4cd38f6a1979050a9bbfcc2bb 100644
--- a/config.sample.yaml
+++ b/config.sample.yaml
@@ -18,6 +18,8 @@ homeservers:
   - name: t2bot.io # This should match the Host header given to the media repo
     downloadRequiresAuth: false # Set to true to require auth on downloads and identicons
     csApi: "https://t2bot.io/" # The base URL to where the homeserver can actually be reached
+    backoffAt: 10 # The number of consecutive failures in calling this homeserver before the
+                  # media repository will start backing off. This defaults to 10 if not given.
 
 # The file upload settings for the media repository
 uploads:
diff --git a/src/github.com/turt2live/matrix-media-repo/client/r0/download.go b/src/github.com/turt2live/matrix-media-repo/client/r0/download.go
index 1391151f603d7d8428d76995279eb4866011106d..c9c3ea5a86b271e22430399a5cf554e65d6a5c78 100644
--- a/src/github.com/turt2live/matrix-media-repo/client/r0/download.go
+++ b/src/github.com/turt2live/matrix-media-repo/client/r0/download.go
@@ -7,6 +7,7 @@ import (
 	"github.com/gorilla/mux"
 	"github.com/sirupsen/logrus"
 	"github.com/turt2live/matrix-media-repo/client"
+	"github.com/turt2live/matrix-media-repo/matrix"
 	"github.com/turt2live/matrix-media-repo/media_cache"
 	"github.com/turt2live/matrix-media-repo/util"
 	"github.com/turt2live/matrix-media-repo/util/errs"
@@ -68,7 +69,7 @@ func ValidateUserCanDownload(r *http.Request, log *logrus.Entry) (bool) {
 	}
 
 	accessToken := util.GetAccessTokenFromRequest(r)
-	userId, err := util.GetUserIdFromToken(r.Context(), r.Host, accessToken)
+	userId, err := matrix.GetUserIdFromToken(r.Context(), r.Host, accessToken)
 	if err != nil {
 		log.Error("Error verifying token: " + err.Error())
 	}
diff --git a/src/github.com/turt2live/matrix-media-repo/client/r0/preview_url.go b/src/github.com/turt2live/matrix-media-repo/client/r0/preview_url.go
index b671fede384b0939deedfd52ef9d1e9afb9a4941..a327abd41e73527888d67cee3b50c58c517f68a1 100644
--- a/src/github.com/turt2live/matrix-media-repo/client/r0/preview_url.go
+++ b/src/github.com/turt2live/matrix-media-repo/client/r0/preview_url.go
@@ -8,6 +8,7 @@ import (
 	"github.com/sirupsen/logrus"
 	"github.com/turt2live/matrix-media-repo/client"
 	"github.com/turt2live/matrix-media-repo/config"
+	"github.com/turt2live/matrix-media-repo/matrix"
 	"github.com/turt2live/matrix-media-repo/services/url_service"
 	"github.com/turt2live/matrix-media-repo/util"
 	"github.com/turt2live/matrix-media-repo/util/errs"
@@ -32,7 +33,7 @@ func PreviewUrl(w http.ResponseWriter, r *http.Request, log *logrus.Entry) inter
 	}
 
 	accessToken := util.GetAccessTokenFromRequest(r)
-	userId, err := util.GetUserIdFromToken(r.Context(), r.Host, accessToken)
+	userId, err := matrix.GetUserIdFromToken(r.Context(), r.Host, accessToken)
 	if err != nil || userId == "" {
 		if err != nil {
 			log.Error("Error verifying token: " + err.Error())
diff --git a/src/github.com/turt2live/matrix-media-repo/client/r0/upload.go b/src/github.com/turt2live/matrix-media-repo/client/r0/upload.go
index 5aff4d06635707925257d1e0309ac59ca2844d68..6f2fc58beb888895671dacb562c4bcf180417b7d 100644
--- a/src/github.com/turt2live/matrix-media-repo/client/r0/upload.go
+++ b/src/github.com/turt2live/matrix-media-repo/client/r0/upload.go
@@ -7,6 +7,7 @@ import (
 
 	"github.com/sirupsen/logrus"
 	"github.com/turt2live/matrix-media-repo/client"
+	"github.com/turt2live/matrix-media-repo/matrix"
 	"github.com/turt2live/matrix-media-repo/services/media_service"
 	"github.com/turt2live/matrix-media-repo/util"
 )
@@ -17,7 +18,7 @@ type MediaUploadedResponse struct {
 
 func UploadMedia(w http.ResponseWriter, r *http.Request, log *logrus.Entry) interface{} {
 	accessToken := util.GetAccessTokenFromRequest(r)
-	userId, err := util.GetUserIdFromToken(r.Context(), r.Host, accessToken)
+	userId, err := matrix.GetUserIdFromToken(r.Context(), r.Host, accessToken)
 	if err != nil || userId == "" {
 		if err != nil {
 			log.Error("Error verifying token: " + err.Error())
diff --git a/src/github.com/turt2live/matrix-media-repo/config/config.go b/src/github.com/turt2live/matrix-media-repo/config/config.go
index 25b922088a4a4c867d17dff4d36d7b4bb2b9c9be..a64d4d2845c6146770c57a3e482bb7564cb64262 100644
--- a/src/github.com/turt2live/matrix-media-repo/config/config.go
+++ b/src/github.com/turt2live/matrix-media-repo/config/config.go
@@ -18,6 +18,7 @@ type HomeserverConfig struct {
 	Name                 string `yaml:"name"`
 	DownloadRequiresAuth bool   `yaml:"downloadRequiresAuth"`
 	ClientServerApi      string `yaml:"csApi"`
+	BackoffAt            int    `yaml:"backoffAt"`
 }
 
 type GeneralConfig struct {
diff --git a/src/github.com/turt2live/matrix-media-repo/matrix/matrix.go b/src/github.com/turt2live/matrix-media-repo/matrix/matrix.go
new file mode 100644
index 0000000000000000000000000000000000000000..df6f39180c13fb766a575c114cfad4de05c67ac6
--- /dev/null
+++ b/src/github.com/turt2live/matrix-media-repo/matrix/matrix.go
@@ -0,0 +1,64 @@
+package matrix
+
+import (
+	"context"
+	"time"
+
+	"github.com/matrix-org/gomatrix"
+	"github.com/rubyist/circuitbreaker"
+	"github.com/turt2live/matrix-media-repo/util"
+)
+
+type userIdResponse struct {
+	UserId string `json:"user_id"`
+}
+
+var breakers = make(map[string]*circuit.Breaker)
+
+func GetUserIdFromToken(ctx context.Context, serverName string, accessToken string) (string, error) {
+	hs := util.GetHomeserverConfig(serverName)
+
+	cb, hasCb := breakers[hs.Name]
+	if !hasCb {
+		backoffAt := int64(hs.BackoffAt)
+		if backoffAt <= 0 {
+			backoffAt = 10 // default to 10 for those who don't have this set
+		}
+		cb = circuit.NewConsecutiveBreaker(backoffAt)
+		breakers[hs.Name] = cb
+	}
+
+	userId := ""
+	var replyError error
+	err := cb.CallContext(ctx, func() error {
+		mtxClient, err := gomatrix.NewClient(hs.ClientServerApi, "", accessToken)
+		if err != nil {
+			return err
+		}
+
+		response := &userIdResponse{}
+		url := mtxClient.BuildURL("/account/whoami")
+		_, err = mtxClient.MakeRequest("GET", url, nil, response)
+		if err != nil {
+			// Unknown token errors should be filtered out explicitly to ensure we don't break on bad requests
+			if httpErr, ok := err.(gomatrix.HTTPError); ok {
+				if respErr, ok := httpErr.WrappedError.(gomatrix.RespError); ok {
+					if respErr.ErrCode == "M_UNKNOWN_TOKEN" {
+						replyError = err // we still want to send the error to the caller though
+						return nil
+					}
+				}
+			}
+			return err
+		}
+
+		userId = response.UserId
+		return nil
+	}, 1*time.Minute)
+
+	if replyError != nil {
+		err = replyError
+	}
+
+	return userId, err
+}
diff --git a/src/github.com/turt2live/matrix-media-repo/util/matrix.go b/src/github.com/turt2live/matrix-media-repo/util/matrix.go
deleted file mode 100644
index 3e20be3788bc88aa9515c5f75960e3c01961bec1..0000000000000000000000000000000000000000
--- a/src/github.com/turt2live/matrix-media-repo/util/matrix.go
+++ /dev/null
@@ -1,28 +0,0 @@
-package util
-
-import (
-	"context"
-
-	"github.com/matrix-org/gomatrix"
-)
-
-type userIdResponse struct {
-	UserId string `json:"user_id"`
-}
-
-func GetUserIdFromToken(ctx context.Context, serverName string, accessToken string) (string, error) {
-	hs := GetHomeserverConfig(serverName)
-	mtxClient, err := gomatrix.NewClient(hs.ClientServerApi, "", accessToken)
-	if err != nil {
-		return "", err
-	}
-
-	response := &userIdResponse{}
-	url := mtxClient.BuildURL("/account/whoami")
-	_, err = mtxClient.MakeRequest("GET", url, nil, response)
-	if err != nil {
-		return "", err
-	}
-
-	return response.UserId, nil
-}
diff --git a/vendor/manifest b/vendor/manifest
index eb2151363ce10cd5c4649bd5296d875063d716c7..f7ad6172037da04e5cba0ba725fbac284290e23a 100644
--- a/vendor/manifest
+++ b/vendor/manifest
@@ -31,6 +31,12 @@
 			"revision": "349dd0209470eabd9514242c688c403c0926d266",
 			"branch": "master"
 		},
+		{
+			"importpath": "github.com/cenk/backoff",
+			"repository": "https://github.com/cenk/backoff",
+			"revision": "2ea60e5f094469f9e65adb9cd103795b73ae743e",
+			"branch": "master"
+		},
 		{
 			"importpath": "github.com/cupcake/sigil",
 			"repository": "https://github.com/cupcake/sigil",
@@ -56,6 +62,12 @@
 			"branch": "master",
 			"path": "/opengraph"
 		},
+		{
+			"importpath": "github.com/facebookgo/clock",
+			"repository": "https://github.com/facebookgo/clock",
+			"revision": "600d898af40aa09a7a93ecb9265d87b0504b6f03",
+			"branch": "master"
+		},
 		{
 			"importpath": "github.com/gorilla/mux",
 			"repository": "https://github.com/gorilla/mux",
@@ -134,6 +146,12 @@
 			"revision": "3bcf86f879c771238f8a67832a1af71308801a47",
 			"branch": "master"
 		},
+		{
+			"importpath": "github.com/rubyist/circuitbreaker",
+			"repository": "https://github.com/rubyist/circuitbreaker",
+			"revision": "2074adba5ddc7d5f7559448a9c3066573521c5bf",
+			"branch": "master"
+		},
 		{
 			"importpath": "github.com/rwcarlsen/goexif",
 			"repository": "https://github.com/rwcarlsen/goexif",