CREATE_SUBSCRIPTION(7pg18)
๐ CREATE_SUBSCRIPTION ๐
okay bestie, welcome to the <strong>CREATE SUBSCRIPTION(7)</strong> page โ PostgreSQL 18.6 Documentation, but make it cute. this is the one where you tell Postgres "hey, go follow that other database's posts, no cap" ๐ซถ
โจ NAME โจ
CREATE_SUBSCRIPTION โ define a new subscription ๐
๐ธ SYNOPSIS ๐ธ
CREATE SUBSCRIPTION subscription_name
CONNECTION 'conninfo'
PUBLICATION publication_name [, ...]
[ WITH ( subscription_parameter [= value] [, ... ] ) ]
look at her. so simple. so powerful. the commas are doing SO much work here bestie. ๐ฆ
๐ DESCRIPTION ๐
okay so CREATE SUBSCRIPTION adds a brand new logical-replication subscription. that's the whole vibe. โจ
the user who creates a subscription becomes the owner of the subscription. like, it's yours now. main character energy. ๐
and the subscription name? it must be distinct from the name of any existing subscription in the current database. no twinning allowed, sorry, there can only be one ๐
a subscription basically represents a replication connection to the publisher. so bestie, it's not just chillin' in your local catalogs โ nope. in addition to adding definitions in the local catalogs, this command normally creates a replication slot on the publisher. it's giving "commitment." ๐ฅ
then a logical replication worker gets started to replicate data for the new subscription โ and the timing? at the commit of the transaction where this command is run. โฐ
โ ๏ธ caveat, queen: the worker does <strong>not</strong> start if the subscription is initially disabled. so if you turn it off from the jump, nothing runs yet. don't come for me, that's just how it is ๐
๐ซถ the prerequisites (yes, there are some, sorry) ๐ซถ
to be able to create a subscription, you must have:
- the privileges of the
pg_create_subscriptionrole โจ - <strong>and</strong>
CREATEprivileges on the current database ๐
both. not one. both. periodt. ๐
๐ where to learn more ๐
additional info about subscriptions and logical replication as a whole lives at Section 29.2 and Chapter 29. go read those, iykyk ๐
โฆand that's just part 1 bestie, we're not done yet โ keep scrolling, there's more coming ๐
โจ PARAMETERS โจ
okay bestie, deep breath โ this is the part where all the lil knobs and dials live. turn them however you want, no judgement ๐
subscription_nameโ the name of your new subscription. that's it, that's the whole thing. pick something cute, you're gonna be saying it a lot ๐CONNECTION 'conninfo'โ thelibpqconnection string that tells Postgres how to actually reach the publisher database. all the deets for building it are in Section 32.1.1 ๐PUBLICATION publication_name [, ...]โ the names of the publications on the publisher that you're subscribing to. yes you can list more than one. comma-separated. go off โจWITH ( subscription_parameter [= value] [, ... ] )โ this clause is where you drop your optional parameters. optional, but honestly? iconic ๐
so the next four parameters control what goes down while the subscription is being created ๐ฑ
connect(boolean) โ says whether theCREATE SUBSCRIPTIONcommand should connect to the publisher at all. default istrue. setting it tofalsewill force the values ofcreate_slot,enabledandcopy_datatofalse. (and no, you cannot combineconnectset tofalsewithcreate_slot,enabled, orcopy_dataset totrueโ that combo is just not happening, bestie ๐ )
and listen, since no connection gets made when this is false, no tables are subscribed. to actually initiate replication you've gotta manually create the replication slot, enable the failover if required, enable the subscription, and refresh the subscription. examples are waiting for you in Section 29.2.3 ๐
create_slot(boolean) โ says whether the command should create the replication slot on the publisher. default istrue.
if you set it to false, you are responsible for creating the publisher's slot some other way. Section 29.2.3 has examples, go look ๐
enabled(boolean) โ says whether the subscription should be actively replicating, or whether it should just be set up but not started yet. default istrue.slot_name(string) โ the name of the publisher's replication slot to use. by default it just uses the name of the subscription as the slot name. easy โจ
setting slot_name to NONE means there will be no replication slot associated with the subscription. such subscriptions must also have both enabled and create_slot set to false. use this when you're gonna create the replication slot later, manually. Section 29.2.3 for examples.
and here's a heads-up that matters: when you set slot_name to a valid name and create_slot to false, the failover property value of the named slot may differ from the counterpart failover parameter you specified in the subscription. always make sure the slot property failover matches the counterpart parameter of the subscription, and vice versa. otherwise the slot on the publisher may behave differently from what these subscription options say โ like, the slot on the publisher could either be synced to the standbys even when the subscription's failover option is disabled, or it could be disabled for sync even when the subscription's failover option is enabled. messy. don't do it ๐ญ
and these ones control the subscription's replication behavior after it's been created ๐ฆ
binary(boolean) โ says whether the subscription will request the publisher to send the data in binary format (as opposed to text). default isfalse. any initial table synchronization copy (seecopy_data) also uses the same format. binary format can be faster than text, but it's less portable across machine architectures and PostgreSQL versions. it's also super data type specific โ for example, it will not allow copying from asmallintcolumn to anintegercolumn, even though that would work totally fine in text format. and even when this option is enabled, only data types that have binary send and receive functions will be transferred in binary. also note: the initial synchronization requires all data types to have binary send and receive functions, otherwise the synchronization will fail (peepCREATE TYPE (CREATE_TYPE(7))for more about send/receive functions).
when you're doing cross-version replication, it could be that the publisher has a binary send function for some data type, but the subscriber is missing a binary receive function for that type. in that case, data transfer will fail, and the binary option just can't be used. periodt ๐
oh and โ if the publisher is a PostgreSQL version before 16, then any initial table synchronization will use text format even if binary = true. no cap.
copy_data(boolean) โ says whether to copy pre-existing data in the publications you're subscribing to when replication starts. default istrue.
if the publications contain WHERE clauses, it will affect what data gets copied. refer to the Notes for details.
and also see Notes for details of how copy_data = true can interact with the origin parameter ๐
streaming(enum) โ says whether to enable streaming of in-progress transactions for this subscription. the default value isparallel, meaning incoming changes are directly applied via one of the parallel apply workers, if available. if no parallel apply worker is free to handle streaming transactions, then the changes get written to temporary files and applied after the transaction is committed. note that if an error happens in a parallel apply worker, the finish LSN of the remote transaction might not be reported in the server log ๐
โ ๏ธ Caution: there's a risk of deadlock when the schemas of the publisher and subscriber differ, although such cases are rare. the apply worker is equipped to retry these transactions automatically. so like, it's handled, but still.
if set to on, the incoming changes are written to temporary files and then applied only after the transaction is committed on the publisher and received by the subscriber.
if set to off, all transactions are fully decoded on the publisher and only then sent to the subscriber as a whole.
synchronous_commit(enum) โ the value of this parameter overrides thesynchronous_commitsetting within this subscription's apply worker processes. the default value isoff.
it is safe to use off for logical replication: if the subscriber loses transactions because of missing synchronization, the data will be sent again from the publisher. ๐
a different setting might be appropriate when doing synchronous logical replication. the logical replication workers report the positions of writes and flushes to the publisher, and when using synchronous replication, the publisher will wait for the actual flush. this means that setting synchronous_commit for the subscriber to off when the subscription is used for synchronous replication might increase the latency for COMMIT on the publisher. in this scenario, it can be advantageous to set synchronous_commit to local or higher. iykyk ๐ง
two_phase(boolean) โ says whether two-phase commit is enabled for this subscription. default isfalse.
when two-phase commit is enabled, prepared transactions are sent to the subscriber at the time of PREPARE TRANSACTION, and are processed as two-phase transactions on the subscriber too. otherwise, prepared transactions are sent to the subscriber only when committed, and are then processed immediately by the subscriber.
the implementation of two-phase commit requires that replication has successfully finished the initial table synchronization phase. so even when two_phase is enabled for a subscription, the internal two-phase state remains temporarily โpendingโ until the initialization phase completes. check column subtwophasestate of pg_subscription to know the actual two-phase state ๐
disable_on_error(boolean) โ says whether the subscription should be automatically disabled if any errors are detected by subscription workers during data replication from the publisher. default isfalse.password_required(boolean) โ if set totrue, connections to the publisher made as a result of this subscription must use password authentication, and the password must be specified as a part of the connection string. this setting is ignored when the subscription is owned by a superuser. default istrue. only superusers can set this value tofalse. ๐run_as_owner(boolean) โ iftrue, all replication actions are performed as the subscription owner. iffalse, replication workers will perform actions on each table as the owner of that table. the latter configuration is generally much more secure; for details, see Section 29.11. default isfalse. ๐origin(string) โ says whether the subscription will request the publisher to only send changes that don't have an origin, or to send changes regardless of origin. settingorigintononemeans the subscription will request the publisher to only send changes that don't have an origin. settingorigintoanymeans the publisher sends changes regardless of their origin. default isany.
see Notes for details of how copy_data = true can interact with the origin parameter ๐
failover(boolean) โ says whether the replication slots associated with the subscription are enabled to be synced to the standbys, so that logical replication can be resumed from the new primary after failover. default isfalse. ๐
oh and one lil shortcut before you go: when you're specifying a parameter of type boolean, the = value part can be omitted, which is equivalent to specifying TRUE. so copy_data alone hits the same as copy_data = true. slay โจ
๐ NOTES ๐
Okay bestie, this is the โจfine printโจ section and honestly it's giving "read me or perish" energy, so let's go ๐
Wanna know how to set up access control between the subscription and the publication instance? Peep Section 29.11, it's all there ๐ซถ
When you're creating a replication slot โ and btw that's the default behavior, no cap โ CREATE SUBSCRIPTION cannot be run inside a transaction block. Periodt. ๐
โโ๏ธ
Now here's a spicy one ๐ฅ If you're creating a subscription that connects to the same database cluster (like, replicating between databases in the same cluster, or replicating within the same database), it will only succeed if the replication slot is not created as part of the same command. Otherwise your CREATE SUBSCRIPTION call will literally just hang. ๐ To make it work, create the replication slot separately โ using the function pg_create_logical_replication_slot with the plugin name pgoutput โ and then create the subscription using the parameter create_slot = false. Section 29.2.3 has examples if you need them. This is an implementation restriction that might get lifted in a future release, so likeโฆ watch this space ๐
If any table in the publication has a WHERE clause, rows where the expression evaluates to false or NULL will not be published. Simple as that.
If your subscription has several publications where the same table got published with different WHERE clauses, a row will be published if any of the expressions (referring to that publish operation) are satisfied. ๐ค
And in the case of different WHERE clauses โ if one of the publications has no WHERE clause (again, referring to that publish operation), or the publication is declared as FOR ALL TABLES or FOR TABLES IN SCHEMA, then rows are always published regardless of what the other expressions say. That one publication is the main character and it overrides everything ๐
If the subscriber is a PostgreSQL version before 15, then any row filtering is ignored during the initial data synchronization phase. In that case, you might wanna consider deleting any initially copied data that would be incompatible with subsequent filtering. Because initial data synchronization does not take into account the publication publish parameter when copying existing table data, some rows may get copied that would not be replicated using DML. Section 29.2.2 has examples ๐
Subscriptions having several publications in which the same table has been published with different column lists are not supported. Not a vibe, just facts. ๐ญ
We allow non-existent publications to be specified so users can add those later. Which means pg_subscription can have non-existent publications. Iconic, honestly.
Now, when you use a subscription parameter combo of copy_data = true and origin = NONE, the initial sync table data gets copied directly from the publisher โ meaning knowledge of the true origin of that data is justโฆ not possible. ๐ If the publisher also has subscriptions, then the copied table data might have originated from further upstream. This scenario gets detected and a WARNING is logged to the user, but heads up: that warning is only an indication of a potential problem. It is the user's responsibility to make the necessary checks to ensure the copied data origins are really as wanted or not. No one else is gonna do it for you, bestie ๐
Wanna find which tables might potentially include non-local origins (due to other subscriptions created on the publisher)? Try this SQL query:
# substitute <pub-names> below with your publication name(s) to be queried
SELECT DISTINCT PT.schemaname, PT.tablename
FROM pg_publication_tables PT
JOIN pg_class C ON (C.relname = PT.tablename)
JOIN pg_namespace N ON (N.nspname = PT.schemaname),
pg_subscription_rel PS
WHERE C.relnamespace = N.oid AND
(PS.srrelid = C.oid OR
C.oid IN (SELECT relid FROM pg_partition_ancestors(PS.srrelid) UNION
SELECT relid FROM pg_partition_tree(PS.srrelid))) AND
PT.pubname IN (<pub-names>);
๐ EXAMPLES ๐
Let's see it in action, shall we? โจ
Example one โ create a subscription to a remote server that replicates tables in the publications mypublication and insert_only, and starts replicating immediately on commit:
CREATE SUBSCRIPTION mysub
CONNECTION 'host=192.168.1.50 port=5432 user=foo dbname=foodb'
PUBLICATION mypublication, insert_only;
Example two โ create a subscription to a remote server that replicates tables in the insert_only publication and does not start replicating until enabled at a later time:
CREATE SUBSCRIPTION mysub
CONNECTION 'host=192.168.1.50 port=5432 user=foo dbname=foodb'
PUBLICATION insert_only
WITH (enabled = false);
See? Easy. Slay. ๐
๐ซ COMPATIBILITY ๐ซ
CREATE SUBSCRIPTION is a PostgreSQL extension. That's it, that's the whole section. It's not standard SQL, it's our special little thing ๐
๐ SEE ALSO ๐
Go read these next, bestie, they're literally the friend group of this command:
ALTER SUBSCRIPTION(ALTER_SUBSCRIPTION(7))DROP SUBSCRIPTION(DROP_SUBSCRIPTION(7))CREATE PUBLICATION(CREATE_PUBLICATION(7))ALTER PUBLICATION(ALTER_PUBLICATION(7))
And that's a wrap on the whole page, fr fr! ๐ฆ This one came from PostgreSQL 18.6, dated 2026 โ so if you're reading this, you're running with the crew that ships CREATE_SUBSCRIPTION(7). Go forth and replicate responsibly, you absolute icon ๐๐
๐ฆ where this page comes from
- opensuse-leap 16.0: postgresql18 18.6-160000.1.1 ยท PostgreSQL
- opensuse-leap 16.0: postgresql18 18.6-160000.1.1 ยท PostgreSQL
- opensuse-leap 16.0: postgresql18 18.6-160000.1.1 ยท PostgreSQL
- opensuse-leap 16.0: postgresql18 18.6-160000.1.1 ยท PostgreSQL
- ๐ girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms