diff --git a/cmd/flux/bootstrap.go b/cmd/flux/bootstrap.go
index b31befd6f15430c16cf1d5db813125d9c57c19e7..b81e357646a11ff12f13f480a7de36f9af32ee50 100644
--- a/cmd/flux/bootstrap.go
+++ b/cmd/flux/bootstrap.go
@@ -60,6 +60,7 @@ type bootstrapFlags struct {
 	requiredComponents []string
 	tokenAuth          bool
 	clusterDomain      string
+	tolerationKeys     []string
 }
 
 const (
@@ -91,6 +92,8 @@ func init() {
 	bootstrapCmd.PersistentFlags().Var(&bootstrapArgs.logLevel, "log-level", bootstrapArgs.logLevel.Description())
 	bootstrapCmd.PersistentFlags().StringVar(&bootstrapArgs.manifestsPath, "manifests", "", "path to the manifest directory")
 	bootstrapCmd.PersistentFlags().StringVar(&bootstrapArgs.clusterDomain, "cluster-domain", rootArgs.defaults.ClusterDomain, "internal cluster domain")
+	bootstrapCmd.PersistentFlags().StringSliceVar(&bootstrapArgs.tolerationKeys, "toleration-keys", nil,
+		"list of toleration keys used to schedule the components pods onto nodes with matching taints")
 	bootstrapCmd.PersistentFlags().MarkHidden("manifests")
 	bootstrapCmd.PersistentFlags().MarkDeprecated("arch", "multi-arch container image is now available for AMD64, ARMv7 and ARM64")
 	rootCmd.AddCommand(bootstrapCmd)
@@ -138,6 +141,7 @@ func generateInstallManifests(targetPath, namespace, tmpDir string, localManifes
 		Timeout:                rootArgs.timeout,
 		TargetPath:             targetPath,
 		ClusterDomain:          bootstrapArgs.clusterDomain,
+		TolerationKeys:         bootstrapArgs.tolerationKeys,
 	}
 
 	if localManifests == "" {
diff --git a/cmd/flux/install.go b/cmd/flux/install.go
index b0d301eba9a0f2eeb0520ff01d842d68d8cf2863..5218055f7bda88beef25d4988104b0421064c6d6 100644
--- a/cmd/flux/install.go
+++ b/cmd/flux/install.go
@@ -34,15 +34,18 @@ import (
 
 var installCmd = &cobra.Command{
 	Use:   "install",
-	Short: "Install the toolkit components",
-	Long: `The install command deploys the toolkit components in the specified namespace.
+	Short: "Install or upgrade Flux",
+	Long: `The install command deploys Flux in the specified namespace.
 If a previous version is installed, then an in-place upgrade will be performed.`,
 	Example: `  # Install the latest version in the flux-system namespace
   flux install --version=latest --namespace=flux-system
 
-  # Dry-run install for a specific version and a series of components
+  # Install a specific version and a series of components
   flux install --dry-run --version=v0.0.7 --components="source-controller,kustomize-controller"
 
+  # Install Flux onto tainted Kubernetes nodes
+  flux install --toleration-keys=node.kubernetes.io/dedicated-to-flux
+
   # Dry-run install with manifests preview
   flux install --dry-run --verbose
 
@@ -66,6 +69,7 @@ var (
 	installArch               flags.Arch
 	installLogLevel           = flags.LogLevel(rootArgs.defaults.LogLevel)
 	installClusterDomain      string
+	installTolerationKeys     []string
 )
 
 func init() {
@@ -91,6 +95,8 @@ func init() {
 	installCmd.Flags().BoolVar(&installNetworkPolicy, "network-policy", rootArgs.defaults.NetworkPolicy,
 		"deny ingress access to the toolkit controllers from other namespaces using network policies")
 	installCmd.Flags().StringVar(&installClusterDomain, "cluster-domain", rootArgs.defaults.ClusterDomain, "internal cluster domain")
+	installCmd.Flags().StringSliceVar(&installTolerationKeys, "toleration-keys", nil,
+		"list of toleration keys used to schedule the components pods onto nodes with matching taints")
 	installCmd.Flags().MarkHidden("manifests")
 	installCmd.Flags().MarkDeprecated("arch", "multi-arch container image is now available for AMD64, ARMv7 and ARM64")
 	rootCmd.AddCommand(installCmd)
@@ -130,6 +136,7 @@ func installCmdRun(cmd *cobra.Command, args []string) error {
 		ManifestFile:           fmt.Sprintf("%s.yaml", rootArgs.namespace),
 		Timeout:                rootArgs.timeout,
 		ClusterDomain:          installClusterDomain,
+		TolerationKeys:         installTolerationKeys,
 	}
 
 	if installManifestsPath == "" {
diff --git a/docs/cmd/flux.md b/docs/cmd/flux.md
index 34b9ea8506cdb89b375223376136c10e28a0038e..6686573d4c80ec94246f407734fa25c222da09a4 100644
--- a/docs/cmd/flux.md
+++ b/docs/cmd/flux.md
@@ -84,7 +84,7 @@ Command line utility for assembling Kubernetes CD pipelines the GitOps way.
 * [flux delete](flux_delete.md)	 - Delete sources and resources
 * [flux export](flux_export.md)	 - Export resources in YAML format
 * [flux get](flux_get.md)	 - Get sources and resources
-* [flux install](flux_install.md)	 - Install the toolkit components
+* [flux install](flux_install.md)	 - Install or upgrade Flux
 * [flux reconcile](flux_reconcile.md)	 - Reconcile sources and resources
 * [flux resume](flux_resume.md)	 - Resume suspended resources
 * [flux suspend](flux_suspend.md)	 - Suspend resources
diff --git a/docs/cmd/flux_bootstrap.md b/docs/cmd/flux_bootstrap.md
index 465edd96c8fd52e383560d0da3570f7fc64fb32b..6ee474cb08a7069c8787daab78c849e9c5f71a67 100644
--- a/docs/cmd/flux_bootstrap.md
+++ b/docs/cmd/flux_bootstrap.md
@@ -19,6 +19,7 @@ The bootstrap sub-commands bootstrap the toolkit components on the targeted Git
       --network-policy             deny ingress access to the toolkit controllers from other namespaces using network policies (default true)
       --registry string            container registry where the toolkit images are published (default "ghcr.io/fluxcd")
       --token-auth                 when enabled, the personal access token will be used instead of SSH deploy key
+      --toleration-keys strings    list of toleration keys used to schedule the components pods onto nodes with matching taints
   -v, --version string             toolkit version (default "latest")
       --watch-all-namespaces       watch for custom resources in all namespaces, if set to false it will only watch the namespace where the toolkit is installed (default true)
 ```
diff --git a/docs/cmd/flux_bootstrap_github.md b/docs/cmd/flux_bootstrap_github.md
index 54c2fa679a1cbe6c8b10bb87f8a71d6103b4ee53..ba185717532983930ece6d6da6670105c890972c 100644
--- a/docs/cmd/flux_bootstrap_github.md
+++ b/docs/cmd/flux_bootstrap_github.md
@@ -74,6 +74,7 @@ flux bootstrap github [flags]
       --registry string            container registry where the toolkit images are published (default "ghcr.io/fluxcd")
       --timeout duration           timeout for this operation (default 5m0s)
       --token-auth                 when enabled, the personal access token will be used instead of SSH deploy key
+      --toleration-keys strings    list of toleration keys used to schedule the components pods onto nodes with matching taints
       --verbose                    print generated objects
   -v, --version string             toolkit version (default "latest")
       --watch-all-namespaces       watch for custom resources in all namespaces, if set to false it will only watch the namespace where the toolkit is installed (default true)
diff --git a/docs/cmd/flux_bootstrap_gitlab.md b/docs/cmd/flux_bootstrap_gitlab.md
index a718b6481bb3d81428f2c1dab2251aee8bd75233..5eb0c96506341cc9cbccc9e090d7d237a869dc3a 100644
--- a/docs/cmd/flux_bootstrap_gitlab.md
+++ b/docs/cmd/flux_bootstrap_gitlab.md
@@ -70,6 +70,7 @@ flux bootstrap gitlab [flags]
       --registry string            container registry where the toolkit images are published (default "ghcr.io/fluxcd")
       --timeout duration           timeout for this operation (default 5m0s)
       --token-auth                 when enabled, the personal access token will be used instead of SSH deploy key
+      --toleration-keys strings    list of toleration keys used to schedule the components pods onto nodes with matching taints
       --verbose                    print generated objects
   -v, --version string             toolkit version (default "latest")
       --watch-all-namespaces       watch for custom resources in all namespaces, if set to false it will only watch the namespace where the toolkit is installed (default true)
diff --git a/docs/cmd/flux_install.md b/docs/cmd/flux_install.md
index 4765e8e00c81930651053fc963e3aa043339e4fd..faad587868abd0ededffc5898938dccc8f6e11a8 100644
--- a/docs/cmd/flux_install.md
+++ b/docs/cmd/flux_install.md
@@ -1,10 +1,10 @@
 ## flux install
 
-Install the toolkit components
+Install or upgrade Flux
 
 ### Synopsis
 
-The install command deploys the toolkit components in the specified namespace.
+The install command deploys Flux in the specified namespace.
 If a previous version is installed, then an in-place upgrade will be performed.
 
 ```
@@ -17,9 +17,12 @@ flux install [flags]
   # Install the latest version in the flux-system namespace
   flux install --version=latest --namespace=flux-system
 
-  # Dry-run install for a specific version and a series of components
+  # Install a specific version and a series of components
   flux install --dry-run --version=v0.0.7 --components="source-controller,kustomize-controller"
 
+  # Install Flux onto tainted Kubernetes nodes
+  flux install --toleration-keys=node.kubernetes.io/dedicated-to-flux
+
   # Dry-run install with manifests preview
   flux install --dry-run --verbose
 
@@ -41,6 +44,7 @@ flux install [flags]
       --log-level logLevel         log level, available options are: (debug, info, error) (default info)
       --network-policy             deny ingress access to the toolkit controllers from other namespaces using network policies (default true)
       --registry string            container registry where the toolkit images are published (default "ghcr.io/fluxcd")
+      --toleration-keys strings    list of toleration keys used to schedule the components pods onto nodes with matching taints
   -v, --version string             toolkit version (default "latest")
       --watch-all-namespaces       watch for custom resources in all namespaces, if set to false it will only watch the namespace where the toolkit is installed (default true)
 ```
diff --git a/docs/guides/installation.md b/docs/guides/installation.md
index c4f9bece7d909a478147fd02b147e7220a868f14..152335f2d0d69dad08e4ae5c585eff08963956b6 100644
--- a/docs/guides/installation.md
+++ b/docs/guides/installation.md
@@ -70,6 +70,10 @@ flux bootstrap <GIT-PROVIDER> \
 If you wish to install a specific version, use the Flux
 [release tag](https://github.com/fluxcd/flux2/releases) e.g. `--version=v0.2.0`.
 
+If you wish to deploy the Flux components onto
+[tainted Kubernetes nodes](https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/),
+you can specify the toleration keys with `--toleration-keys=node.kubernetes.io/dedicated-to-flux`.
+
 With `--path` you can configure the directory which will be used to reconcile the target cluster.
 To control multiple clusters from the same Git repository, you have to set a unique path per
 cluster e.g. `clusters/staging` and `clusters/production`:
diff --git a/pkg/manifestgen/install/install_test.go b/pkg/manifestgen/install/install_test.go
index 4fa6daf911e6e452b39137909954a9dc8fc6059a..834b26d4d2aa9727fd03de05bb1f301de757ac5d 100644
--- a/pkg/manifestgen/install/install_test.go
+++ b/pkg/manifestgen/install/install_test.go
@@ -24,6 +24,7 @@ import (
 
 func TestGenerate(t *testing.T) {
 	opts := MakeDefaultOptions()
+	opts.TolerationKeys = []string{"node.kubernetes.io/controllers"}
 	output, err := Generate(opts)
 	if err != nil {
 		t.Fatal(err)
@@ -36,5 +37,9 @@ func TestGenerate(t *testing.T) {
 		}
 	}
 
+	if !strings.Contains(output.Content, opts.TolerationKeys[0]) {
+		t.Errorf("toleration key '%s' not found", opts.TolerationKeys[0])
+	}
+
 	fmt.Println(output)
 }
diff --git a/pkg/manifestgen/install/options.go b/pkg/manifestgen/install/options.go
index 0a15f821c6cfafd2d48d423859698058e506bfee..a456007b8b418381544c40121dfa78ea4df265d6 100644
--- a/pkg/manifestgen/install/options.go
+++ b/pkg/manifestgen/install/options.go
@@ -35,6 +35,7 @@ type Options struct {
 	Timeout                time.Duration
 	TargetPath             string
 	ClusterDomain          string
+	TolerationKeys         []string
 }
 
 func MakeDefaultOptions() Options {
diff --git a/pkg/manifestgen/install/templates.go b/pkg/manifestgen/install/templates.go
index 316435d14a6592272a476990c89814aca8a0f198..1dcec5c9fa49e5380cf8da476329624dc8c42762 100644
--- a/pkg/manifestgen/install/templates.go
+++ b/pkg/manifestgen/install/templates.go
@@ -137,6 +137,13 @@ spec:
       imagePullSecrets:
        - name: {{.ImagePullSecret}}
 {{- end }}
+{{ if gt (len .TolerationKeys) 0 }}
+      tolerations:
+{{- range $i, $key := .TolerationKeys }}
+       - key: "{{$key}}"
+         operator: "Exists"
+{{- end }}
+{{- end }}
 `
 
 var labelsTmpl = `---