diff --git a/CHANGELOG.md b/CHANGELOG.md
index 24945173659483238f275e308914a50b6d63fb89..8865247ed3f498cf6ca808c22f350be42ac24a84 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -13,6 +13,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
 * Add apng image support. Thanks @Sorunome!
 * Experimental support for Redis as a cache (in preparation for proper load balancing/HA support).
 * Added oEmbed URL preview support.
+* Added support for dynamic thumbnails.
 
 ### Changed
 
diff --git a/common/config/conf_domain.go b/common/config/conf_domain.go
index 9f7ff5b7951ad968af623be27eb7648d2b5949ff..f705b3709084aa0681a20d6d3ef4a177c61b5f43 100644
--- a/common/config/conf_domain.go
+++ b/common/config/conf_domain.go
@@ -61,6 +61,7 @@ func NewDefaultDomainConfig() DomainRepoConfig {
 				{640, 480},
 				{800, 600},
 			},
+			DynamicSizing: false,
 			Types: []string{
 				"image/jpeg",
 				"image/jpg",
diff --git a/common/config/conf_main.go b/common/config/conf_main.go
index b3b45cd446a6be14246bece23fd0826cc4bfcb36..d082ff13502b00de9e0d6deae892bf46c56e0bf7 100644
--- a/common/config/conf_main.go
+++ b/common/config/conf_main.go
@@ -96,6 +96,7 @@ func NewDefaultMainConfig() MainRepoConfig {
 					{640, 480},
 					{800, 600},
 				},
+				DynamicSizing: false,
 				Types: []string{
 					"image/jpeg",
 					"image/jpg",
diff --git a/common/config/models_domain.go b/common/config/models_domain.go
index fd9bf3034d9370bbf04dc3f722778d23b2fddb7a..39f8d5e8284c97fcc9aaae6d5a3647e7fea0ec6d 100644
--- a/common/config/models_domain.go
+++ b/common/config/models_domain.go
@@ -29,6 +29,7 @@ type ThumbnailsConfig struct {
 	Types               []string        `yaml:"types,flow"`
 	MaxAnimateSizeBytes int64           `yaml:"maxAnimateSizeBytes"`
 	Sizes               []ThumbnailSize `yaml:"sizes,flow"`
+	DynamicSizing bool `yaml:"dynamicSizing"`
 	AllowAnimated       bool            `yaml:"allowAnimated"`
 	DefaultAnimated     bool            `yaml:"defaultAnimated"`
 	StillFrame          float32         `yaml:"stillFrame"`
diff --git a/config.sample.yaml b/config.sample.yaml
index 0b0d71f10909036b7947eeede808b7de50c97780..81a634d0b52dedd208a52b00cb400b70882e3c4a 100644
--- a/config.sample.yaml
+++ b/config.sample.yaml
@@ -350,6 +350,12 @@ thumbnails:
     - width: 800
       height: 600
 
+  # To allow for thumbnails to be any size, not just in the sizes specified above, set this to
+  # true (default false). When enabled, whatever size requested by the client will be generated
+  # up to a maximum of the largest possible dimensions in the `sizes` list. For best results,
+  # specify only one size in the `sizes` list when this option is enabled.
+  dynamicSizing: false
+
   # The content types to thumbnail when requested. Types that are not supported by the media repo
   # will not be thumbnailed (adding application/json here won't work). Clients may still not request
   # thumbnails for these types - this won't make clients automatically thumbnail these file types.
diff --git a/controllers/thumbnail_controller/thumbnail_controller.go b/controllers/thumbnail_controller/thumbnail_controller.go
index 78ced08bf1eefe60f5344fbf93b53e2e8b4e9602..e1d0d4441fa471731e099d1684f5f76b2c0738f6 100644
--- a/controllers/thumbnail_controller/thumbnail_controller.go
+++ b/controllers/thumbnail_controller/thumbnail_controller.go
@@ -241,6 +241,10 @@ func pickThumbnailDimensions(desiredWidth int, desiredHeight int, desiredMethod
 		}
 	}
 
+	if ctx.Config.Thumbnails.DynamicSizing {
+		return util.MinInt(largestWidth, desiredWidth), util.MinInt(largestHeight, desiredHeight), desiredMethod, nil
+	}
+
 	// Use the largest dimensions available if we didn't find anything
 	if !foundSize {
 		targetWidth = largestWidth
diff --git a/util/math.go b/util/math.go
index 9e460ceb3588c96e8308f37d80b4ae9ca8b33ed0..cb39ce0210840d87ce9868e15d5c4474dfc040be 100644
--- a/util/math.go
+++ b/util/math.go
@@ -7,6 +7,13 @@ func MaxInt(a int, b int) int {
 	return b
 }
 
+func MinInt(a int, b int) int {
+	if a < b {
+		return a
+	}
+	return b
+}
+
 func MinFloat32(a float32, b float32) float32 {
 	if a < b {
 		return a