diff --git a/README.md b/README.md
index 9bd663c6046eaa6110acced8760a19c5e7b44ab7..a769053035a60254302d463ed92ef7664935a604 100644
--- a/README.md
+++ b/README.md
@@ -87,7 +87,16 @@ By default, the operator watches the namespace it is deployed to. You can change
 
 Note that for an operator to manage pods in the watched namespace, the operator's service account (as specified in the operator deployment manifest) has to have appropriate privileges to access the watched namespace. The operator may not be able to function in the case it watches all namespaces but lacks access rights to any of them (except Kubernetes system namespaces like `kube-system`). The reason is that for multiple namespaces operations such as 'list pods' execute at the cluster scope and fail at the first violation of access rights.
 
-The watched namespace also needs to have a (possibly different) service account in the case database pods need to talk to the Kubernetes API (e.g. when using Kubernetes-native configuration of Patroni).
+The watched namespace also needs to have a (possibly different) service account in the case database pods need to talk to the Kubernetes API (e.g. when using Kubernetes-native configuration of Patroni). The operator checks that the `pod_service_account_name` exists in the target namespace, and, if not, deploys there the `pod_service_account_definition` from the operator [`Config`](pkg/util/config/config.go) with the default value of:
+
+```yaml
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+ name: operator
+```
+
+ In this definition, the operator overwrites the account's name to match `pod_service_account_name` and the `default` namespace to match the target namespace. The operator  performs **no** further syncing of this account.
 
 ### Create ConfigMap
 
diff --git a/manifests/configmap.yaml b/manifests/configmap.yaml
index 7d5c742c8c8863e5851f6cfedd3b7966037859c2..f3b79e67b61f2dfac645f9af66369b26ab1f6f2d 100644
--- a/manifests/configmap.yaml
+++ b/manifests/configmap.yaml
@@ -7,7 +7,6 @@ data:
   # if neither is set or evaluates to the empty string, listen to the operator's own namespace
   # if set to the "*", listen to all namespaces
   # watched_namespace: development
-  service_account_name: operator
   cluster_labels: application:spilo
   cluster_name_label: version
   pod_role_label: spilo-role
diff --git a/pkg/cluster/cluster.go b/pkg/cluster/cluster.go
index bfb8e35d7778e1515250942175054aa9325121de..b6251eafc824979cb6ce05c1134fd167629bfa3e 100644
--- a/pkg/cluster/cluster.go
+++ b/pkg/cluster/cluster.go
@@ -42,6 +42,7 @@ type Config struct {
 	OpConfig            config.Config
 	RestConfig          *rest.Config
 	InfrastructureRoles map[string]spec.PgUser // inherited from the controller
+	PodServiceAccount   *v1.ServiceAccount
 }
 
 type kubeResources struct {
@@ -194,6 +195,39 @@ func (c *Cluster) initUsers() error {
 	return nil
 }
 
+/*
+  Ensures the service account required by StatefulSets to create pods exists in a namespace before a PG cluster is created there so that a user does not have to deploy the account manually.
+
+  The operator does not sync these accounts after creation.
+*/
+func (c *Cluster) createPodServiceAccounts() error {
+
+	podServiceAccountName := c.Config.OpConfig.PodServiceAccountName
+	_, err := c.KubeClient.ServiceAccounts(c.Namespace).Get(podServiceAccountName, metav1.GetOptions{})
+
+	if err != nil {
+
+		c.setProcessName(fmt.Sprintf("creating pod service account in the namespace %v", c.Namespace))
+
+		c.logger.Infof("the pod service account %q cannot be retrieved in the namespace %q. Trying to deploy the account.", podServiceAccountName, c.Namespace)
+
+		// get a separate copy of service account
+		// to prevent a race condition when setting a namespace for many clusters
+		sa := *c.PodServiceAccount
+		_, err = c.KubeClient.ServiceAccounts(c.Namespace).Create(&sa)
+		if err != nil {
+			return fmt.Errorf("cannot deploy the pod service account %q defined in the config map to the %q namespace: %v", podServiceAccountName, c.Namespace, err)
+		}
+
+		c.logger.Infof("successfully deployed the pod service account %q to the %q namespace", podServiceAccountName, c.Namespace)
+
+	} else {
+		c.logger.Infof("successfully found the service account %q used to create pods to the namespace %q", podServiceAccountName, c.Namespace)
+	}
+
+	return nil
+}
+
 // Create creates the new kubernetes objects associated with the cluster.
 func (c *Cluster) Create() error {
 	c.mu.Lock()
@@ -256,6 +290,11 @@ func (c *Cluster) Create() error {
 	}
 	c.logger.Infof("pod disruption budget %q has been successfully created", util.NameFromMeta(pdb.ObjectMeta))
 
+	if err = c.createPodServiceAccounts(); err != nil {
+		return fmt.Errorf("could not create pod service account %v : %v", c.OpConfig.PodServiceAccountName, err)
+	}
+	c.logger.Infof("pod service accounts have been successfully synced")
+
 	if c.Statefulset != nil {
 		return fmt.Errorf("statefulset already exists in the cluster")
 	}
diff --git a/pkg/cluster/k8sres.go b/pkg/cluster/k8sres.go
index cf16bb39aa4a60a23d68fa61977507a8d88335ef..2b1460643d2128f8df11eea423162c59c5904114 100644
--- a/pkg/cluster/k8sres.go
+++ b/pkg/cluster/k8sres.go
@@ -435,7 +435,7 @@ func (c *Cluster) generatePodTemplate(
 	terminateGracePeriodSeconds := int64(c.OpConfig.PodTerminateGracePeriod.Seconds())
 
 	podSpec := v1.PodSpec{
-		ServiceAccountName:            c.OpConfig.ServiceAccountName,
+		ServiceAccountName:            c.OpConfig.PodServiceAccountName,
 		TerminationGracePeriodSeconds: &terminateGracePeriodSeconds,
 		Containers:                    []v1.Container{container},
 		Tolerations:                   c.tolerations(tolerationsSpec),
diff --git a/pkg/controller/controller.go b/pkg/controller/controller.go
index d19da5b84cb153c6c8ff115afd02df2bd4584a62..7b309a547f34e139eeee93b65d31ebf7bdffc221 100644
--- a/pkg/controller/controller.go
+++ b/pkg/controller/controller.go
@@ -8,6 +8,7 @@ import (
 	"github.com/Sirupsen/logrus"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/types"
+	"k8s.io/client-go/kubernetes/scheme"
 	"k8s.io/client-go/pkg/api/v1"
 	"k8s.io/client-go/tools/cache"
 
@@ -50,6 +51,8 @@ type Controller struct {
 	lastClusterSyncTime int64
 
 	workerLogs map[uint32]ringlog.RingLogger
+
+	PodServiceAccount *v1.ServiceAccount
 }
 
 // NewController creates a new controller
@@ -113,11 +116,46 @@ func (c *Controller) initOperatorConfig() {
 	if scalyrAPIKey != "" {
 		c.opConfig.ScalyrAPIKey = scalyrAPIKey
 	}
+
+}
+
+func (c *Controller) initPodServiceAccount() {
+
+	if c.opConfig.PodServiceAccountDefinition == "" {
+		c.opConfig.PodServiceAccountDefinition = `
+		{ "apiVersion": "v1", 
+		  "kind": "ServiceAccount", 
+		  "metadata": { 
+				 "name": "operator" 
+		   }
+		}`
+	}
+
+	// re-uses k8s internal parsing. See k8s client-go issue #193 for explanation
+	decode := scheme.Codecs.UniversalDeserializer().Decode
+	obj, groupVersionKind, err := decode([]byte(c.opConfig.PodServiceAccountDefinition), nil, nil)
+
+	switch {
+	case err != nil:
+		panic(fmt.Errorf("Unable to parse pod service account definiton from the operator config map: %v", err))
+	case groupVersionKind.Kind != "ServiceAccount":
+		panic(fmt.Errorf("pod service account definiton in the operator config map defines another type of resource: %v", groupVersionKind.Kind))
+	default:
+		c.PodServiceAccount = obj.(*v1.ServiceAccount)
+		if c.PodServiceAccount.Name != c.opConfig.PodServiceAccountName {
+			c.logger.Warnf("in the operator config map, the pod service account name %v does not match the name %v given in the account definition; using the former for consistency", c.opConfig.PodServiceAccountName, c.PodServiceAccount.Name)
+			c.PodServiceAccount.Name = c.opConfig.PodServiceAccountName
+		}
+		c.PodServiceAccount.Namespace = ""
+	}
+
+	// actual service accounts are deployed at the time of Postgres/Spilo cluster creation
 }
 
 func (c *Controller) initController() {
 	c.initClients()
 	c.initOperatorConfig()
+	c.initPodServiceAccount()
 
 	c.initSharedInformers()
 
diff --git a/pkg/controller/util.go b/pkg/controller/util.go
index 69124c111621466bdfb26d8eec61b2e9af083c4c..5e46e93eb8ec543c551f159245bc8f9da04d295b 100644
--- a/pkg/controller/util.go
+++ b/pkg/controller/util.go
@@ -26,6 +26,7 @@ func (c *Controller) makeClusterConfig() cluster.Config {
 		RestConfig:          c.config.RestConfig,
 		OpConfig:            config.Copy(c.opConfig),
 		InfrastructureRoles: infrastructureRoles,
+		PodServiceAccount:   c.PodServiceAccount,
 	}
 }
 
diff --git a/pkg/util/config/config.go b/pkg/util/config/config.go
index 0e653ce0b2aebfa0e8c948671126963ca0721d3d..b101c6f082ea713831cab049b3bd345143004ab5 100644
--- a/pkg/util/config/config.go
+++ b/pkg/util/config/config.go
@@ -67,21 +67,25 @@ type Config struct {
 	Resources
 	Auth
 	Scalyr
-	WatchedNamespace          string `name:"watched_namespace"` // special values: "*" means 'watch all namespaces', the empty string "" means 'watch a namespace where operator is deployed to'
-	EtcdHost                  string `name:"etcd_host" default:"etcd-client.default.svc.cluster.local:2379"`
-	DockerImage               string `name:"docker_image" default:"registry.opensource.zalan.do/acid/spiloprivate-9.6:1.2-p4"`
-	ServiceAccountName        string `name:"service_account_name" default:"operator"`
-	DbHostedZone              string `name:"db_hosted_zone" default:"db.example.com"`
-	EtcdScope                 string `name:"etcd_scope" default:"service"`
-	WALES3Bucket              string `name:"wal_s3_bucket"`
-	KubeIAMRole               string `name:"kube_iam_role"`
-	DebugLogging              bool   `name:"debug_logging" default:"true"`
-	EnableDBAccess            bool   `name:"enable_database_access" default:"true"`
-	EnableTeamsAPI            bool   `name:"enable_teams_api" default:"true"`
-	EnableTeamSuperuser       bool   `name:"enable_team_superuser" default:"false"`
-	TeamAdminRole             string `name:"team_admin_role" default:"admin"`
-	EnableMasterLoadBalancer  bool   `name:"enable_master_load_balancer" default:"true"`
-	EnableReplicaLoadBalancer bool   `name:"enable_replica_load_balancer" default:"false"`
+
+	WatchedNamespace string `name:"watched_namespace"` // special values: "*" means 'watch all namespaces', the empty string "" means 'watch a namespace where operator is deployed to'
+	EtcdHost         string `name:"etcd_host" default:"etcd-client.default.svc.cluster.local:2379"`
+	DockerImage      string `name:"docker_image" default:"registry.opensource.zalan.do/acid/spiloprivate-9.6:1.2-p4"`
+	// default name `operator` enables backward compatibility with the older ServiceAccountName field
+	PodServiceAccountName string `name:"pod_service_account_name" default:"operator"`
+	// value of this string must be valid JSON or YAML; see initPodServiceAccount
+	PodServiceAccountDefinition string `name:"pod_service_account_definition" default:""`
+	DbHostedZone                string `name:"db_hosted_zone" default:"db.example.com"`
+	EtcdScope                   string `name:"etcd_scope" default:"service"`
+	WALES3Bucket                string `name:"wal_s3_bucket"`
+	KubeIAMRole                 string `name:"kube_iam_role"`
+	DebugLogging                bool   `name:"debug_logging" default:"true"`
+	EnableDBAccess              bool   `name:"enable_database_access" default:"true"`
+	EnableTeamsAPI              bool   `name:"enable_teams_api" default:"true"`
+	EnableTeamSuperuser         bool   `name:"enable_team_superuser" default:"false"`
+	TeamAdminRole               string `name:"team_admin_role" default:"admin"`
+	EnableMasterLoadBalancer    bool   `name:"enable_master_load_balancer" default:"true"`
+	EnableReplicaLoadBalancer   bool   `name:"enable_replica_load_balancer" default:"false"`
 	// deprecated and kept for backward compatibility
 	EnableLoadBalancer       *bool             `name:"enable_load_balancer" default:"true"`
 	MasterDNSNameFormat      stringTemplate    `name:"master_dns_name_format" default:"{cluster}.{team}.{hostedzone}"`