[{"data":1,"prerenderedAt":757},["ShallowReactive",2],{"docs-\u002Fdocs\u002Fconnections\u002Fyugabytedb":3},{"id":4,"title":5,"body":6,"description":748,"extension":749,"meta":750,"navigation":751,"path":752,"redirect":753,"seo":754,"stem":755,"__hash__":756},"docs\u002Fdocs\u002Fconnections\u002Fyugabytedb.md","YugabyteDB Guide",{"type":7,"value":8,"toc":734},"minimark",[9,13,25,37,48,55,60,114,117,122,252,273,277,288,292,302,318,324,327,331,342,349,364,410,413,431,435,453,459,462,495,501,504,508,513,632,639,674,678,697,708,712,721,727,730],[10,11,5],"h1",{"id":12},"yugabytedb-guide",[14,15,16,17,24],"p",{},"Use this page when a PostgreSQL connection in DBConvert Streams points at\n",[18,19,23],"a",{"href":20,"rel":21},"https:\u002F\u002Fdocs.yugabyte.com\u002F",[22],"nofollow","YugabyteDB"," through its YSQL API.",[14,26,27,28,32,33,36],{},"YugabyteDB is PostgreSQL-compatible at the top and distributed underneath: it reuses the\nPostgreSQL query layer, so ",[29,30,31],"code",{},"SELECT version()"," answers with something like\n",[29,34,35],{},"PostgreSQL 15.12-YB-2026.1.1.1",", and stores rows in its own DocDB tablets rather than in\nPostgreSQL's files. The standard connection form applies, and everything on this page comes\nfrom the places where those two halves disagree.",[14,38,39,40,43,44,47],{},"YSQL listens on port ",[29,41,42],{},"5433",", not ",[29,45,46],{},"5432",".",[14,49,50,51,54],{},"Measured against a self-managed YugabyteDB ",[29,52,53],{},"2026.1.1.1",". YugabyteDB Aeon, the managed\nservice, has not been tested.",[56,57,59],"h2",{"id":58},"what-works","What works",[61,62,63,76],"table",{},[64,65,66],"thead",{},[67,68,69,73],"tr",{},[70,71,72],"th",{},"Direction",[70,74,75],{},"Supported",[77,78,79,88,95,102],"tbody",{},[67,80,81,85],{},[82,83,84],"td",{},"YugabyteDB as target, Load",[82,86,87],{},"Yes",[67,89,90,93],{},[82,91,92],{},"YugabyteDB as target, CDC",[82,94,87],{},[67,96,97,100],{},[82,98,99],{},"YugabyteDB as source, Load",[82,101,87],{},[67,103,104,107],{},[82,105,106],{},"YugabyteDB as source, CDC",[82,108,109,110],{},"Yes - after ",[18,111,113],{"href":112},"#yugabytedb-as-a-cdc-source","three prerequisites",[14,115,116],{},"A Load run creates the tables together with their primary keys, indexes and foreign keys.",[118,119,121],"h3",{"id":120},"mysql-type-mapping","MySQL type mapping",[61,123,124,136],{},[64,125,126],{},[67,127,128,131,133],{},[70,129,130],{},"MySQL",[70,132,23],{},[70,134,135],{},"Note",[77,137,138,152,167,181,195,209,223,237],{},[67,139,140,145,150],{},[82,141,142],{},[29,143,144],{},"YEAR",[82,146,147],{},[29,148,149],{},"smallint",[82,151],{},[67,153,154,159,164],{},[82,155,156],{},[29,157,158],{},"ENUM",[82,160,161],{},[29,162,163],{},"text",[82,165,166],{},"labels are kept, the restriction is not",[67,168,169,174,178],{},[82,170,171],{},[29,172,173],{},"SET",[82,175,176],{},[29,177,163],{},[82,179,180],{},"the same comma-separated string",[67,182,183,188,193],{},[82,184,185],{},[29,186,187],{},"BLOB",[82,189,190],{},[29,191,192],{},"bytea",[82,194],{},[67,196,197,202,207],{},[82,198,199],{},[29,200,201],{},"TINYINT(1)",[82,203,204],{},[29,205,206],{},"boolean",[82,208],{},[67,210,211,216,221],{},[82,212,213],{},[29,214,215],{},"DECIMAL",[82,217,218],{},[29,219,220],{},"numeric",[82,222],{},[67,224,225,230,235],{},[82,226,227],{},[29,228,229],{},"TIMESTAMP",[82,231,232],{},[29,233,234],{},"timestamp without time zone",[82,236],{},[67,238,239,244,249],{},[82,240,241],{},[29,242,243],{},"smallint unsigned",[82,245,246],{},[29,247,248],{},"integer",[82,250,251],{},"widened to the next signed type",[253,254,257],"alert",{"title":255,"type":256},"ENUM and SET keep their values, not their constraint","info",[14,258,259,260,262,263,265,266,268,269,272],{},"A MySQL ",[29,261,158],{}," column arrives as ",[29,264,163],{}," holding the same labels, and a ",[29,267,173],{}," column as the\nsame comma-separated string. Which values are allowed is not carried over. Add a ",[29,270,271],{},"CHECK","\nconstraint on the target if you need it enforced.",[56,274,276],{"id":275},"yugabytedb-as-a-cdc-source","YugabyteDB as a CDC source",[14,278,279,280,283,284,287],{},"YugabyteDB implements the PostgreSQL replication protocol, and DBConvert Streams reads it\nwith plain ",[29,281,282],{},"pgoutput"," - no Kafka Connect, no Flink, and not YugabyteDB's own ",[29,285,286],{},"yboutput","\nplugin. Three things have to be true first, and all three are on the YugabyteDB side.",[118,289,291],{"id":290},"_1-replica-identity-on-every-replicated-table","1. Replica identity on every replicated table",[14,293,294,295,298,299,301],{},"YugabyteDB gives a new table the replica identity ",[29,296,297],{},"CHANGE",", which does not exist in\nPostgreSQL and which ",[29,300,282],{}," cannot encode. Set a PostgreSQL-compatible identity before\nthe stream is created:",[303,304,309],"pre",{"className":305,"code":306,"language":307,"meta":308,"style":308},"language-sql shiki shiki-themes github-light github-dark","ALTER TABLE public.orders REPLICA IDENTITY DEFAULT;\n","sql","",[29,310,311],{"__ignoreMap":308},[312,313,316],"span",{"class":314,"line":315},"line",1,[312,317,306],{},[14,319,320,323],{},[29,321,322],{},"FULL"," works too. The order matters: YugabyteDB captures a table's replica identity when the\nreplication slot is created, so changing it afterwards does not affect a stream that already\nexists.",[14,325,326],{},"DBConvert Streams checks this before it creates a publication or a slot and stops with the\ntable name and the statement to run, rather than failing mid-stream.",[118,328,330],{"id":329},"_2-the-before-image-flag-on-the-tservers","2. The before-image flag on the tservers",[14,332,333,334,337,338,341],{},"With its default settings YugabyteDB refuses to produce a before-image for an ",[29,335,336],{},"UPDATE"," or a\n",[29,339,340],{},"DELETE"," and terminates the replication stream:",[303,343,347],{"className":344,"code":346,"language":163,"meta":308},[345],"language-text","ERROR: Failed to get the beforeimage for tablet_id: 9e37b58654fa4280b5b5e434f9bbf099\n",[29,348,346],{"__ignoreMap":308},[14,350,351,352,355,356,359,360,363],{},"The fix is a tserver flag, ",[29,353,354],{},"cdc_send_null_before_image_if_not_exists",", which defaults to\n",[29,357,358],{},"false",". Set it to ",[29,361,362],{},"true"," and YugabyteDB sends a null before-image instead of failing:",[303,365,369],{"className":366,"code":367,"language":368,"meta":308,"style":308},"language-bash shiki shiki-themes github-light github-dark","yb-ts-cli --server_address=\u003Ctserver-host>:9100 \\\n  set_flag cdc_send_null_before_image_if_not_exists true\n","bash",[29,370,371,397],{"__ignoreMap":308},[312,372,373,377,381,385,388,391,394],{"class":314,"line":315},[312,374,376],{"class":375},"sScJk","yb-ts-cli",[312,378,380],{"class":379},"sj4cs"," --server_address=",[312,382,384],{"class":383},"szBVR","\u003C",[312,386,387],{"class":379},"tserver-host",[312,389,390],{"class":383},">",[312,392,393],{"class":379},":9100",[312,395,396],{"class":379}," \\\n",[312,398,400,404,407],{"class":314,"line":399},2,[312,401,403],{"class":402},"sZZnC","  set_flag",[312,405,406],{"class":402}," cdc_send_null_before_image_if_not_exists",[312,408,409],{"class":379}," true\n",[14,411,412],{},"Add it to the tserver flags of a cluster you start yourself so it survives a restart.",[253,414,417],{"title":415,"type":416},"No client works around this one","warning",[14,418,419,420,423,424,427,428,430],{},"This is not specific to DBConvert Streams. PostgreSQL's own ",[29,421,422],{},"pg_recvlogical"," fails the same\nway on the same slot, with ",[29,425,426],{},"REPLICA IDENTITY DEFAULT"," and with ",[29,429,322],{},". Until the flag is\nset, nothing can read updates or deletes out of that cluster over the PostgreSQL protocol.",[118,432,434],{"id":433},"_3-the-intra-transactional-before-image-flag","3. The intra-transactional before-image flag",[14,436,437,440,441,443,444,448,449,452],{},[29,438,439],{},"cdc_enable_intra_transactional_before_image"," also defaults to ",[29,442,358],{},". Without it, a row that\nis inserted and then updated ",[445,446,447],"strong",{},"inside the same transaction"," arrives with the columns that\nupdate did not touch set to null. What you see is a run that stops on a ",[29,450,451],{},"NOT NULL"," column:",[303,454,457],{"className":455,"code":456,"language":163,"meta":308},[345],"ERROR: null value in column \"first_name\" of relation \"actor\" violates not-null constraint\n",[29,458,456],{"__ignoreMap":308},[14,460,461],{},"On a nullable column there is no error and the stored value is simply replaced, which is\nworse. A row updated in its own transaction is unaffected either way, so a quick test passes\nand production does not.",[303,463,465],{"className":366,"code":464,"language":368,"meta":308,"style":308},"yb-ts-cli --server_address=\u003Ctserver-host>:9100 \\\n  set_flag --force cdc_enable_intra_transactional_before_image true\n",[29,466,467,483],{"__ignoreMap":308},[312,468,469,471,473,475,477,479,481],{"class":314,"line":315},[312,470,376],{"class":375},[312,472,380],{"class":379},[312,474,384],{"class":383},[312,476,387],{"class":379},[312,478,390],{"class":383},[312,480,393],{"class":379},[312,482,396],{"class":379},[312,484,485,487,490,493],{"class":314,"line":399},[312,486,403],{"class":402},[312,488,489],{"class":379}," --force",[312,491,492],{"class":402}," cdc_enable_intra_transactional_before_image",[312,494,409],{"class":379},[14,496,497,500],{},[29,498,499],{},"--force"," is required: unlike the first flag, this one is not marked safe to change at\nruntime. On a cluster you start yourself, set it in the tserver flags instead.",[14,502,503],{},"With all three in place, a stream delivers the initial snapshot and then inserts, updates and\ndeletes as they happen, including a transaction that does several of them to the same table.",[56,505,507],{"id":506},"postgresql-features-ysql-does-not-have","PostgreSQL features YSQL does not have",[14,509,510,511,47],{},"These are absent or behave differently, so a schema that uses them needs a decision before\nit moves. All verified on ",[29,512,53],{},[61,514,515,524],{},[64,516,517],{},[67,518,519,522],{},[70,520,521],{},"Feature",[70,523,23],{},[77,525,526,540,548,560,567,577,585,599,613,624],{},[67,527,528,531],{},[82,529,530],{},"GiST indexes",[82,532,533,534,539],{},"Not supported (",[18,535,538],{"href":536,"rel":537},"https:\u002F\u002Fgithub.com\u002Fyugabyte\u002Fyugabyte-db\u002Fissues\u002F1337",[22],"yugabyte-db#1337",")",[67,541,542,545],{},[82,543,544],{},"BRIN indexes",[82,546,547],{},"Not supported",[67,549,550,553],{},[82,551,552],{},"HASH indexes",[82,554,555,556,559],{},"Silently substituted with YugabyteDB's own ",[29,557,558],{},"lsm"," access method",[67,561,562,565],{},[82,563,564],{},"GIN indexes",[82,566,75],{},[67,568,569,575],{},[82,570,571,574],{},[29,572,573],{},"EXCLUDE"," constraints",[82,576,547],{},[67,578,579,582],{},[82,580,581],{},"PostGIS",[82,583,584],{},"Extension not available",[67,586,587,597],{},[82,588,589,592,593,596],{},[29,590,591],{},"ctid",", ",[29,594,595],{},"xmin"," system columns",[82,598,547],{},[67,600,601,610],{},[82,602,603,606,607],{},[29,604,605],{},"LISTEN"," \u002F ",[29,608,609],{},"NOTIFY",[82,611,612],{},"Disabled",[67,614,615,621],{},[82,616,617,620],{},[29,618,619],{},"UNLOGGED"," tables",[82,622,623],{},"Accepted and ignored",[67,625,626,629],{},[82,627,628],{},"Table inheritance",[82,630,631],{},"Works, marked beta by YugabyteDB",[14,633,634,635,638],{},"A GiST index on a ",[29,636,637],{},"tsvector"," column is the common case in a PostgreSQL schema. GIN is the\nequivalent YSQL accepts, so that index has to be recreated as GIN rather than carried over.",[14,640,641,642,645,646,592,649,652,653,656,657,592,660,652,663,592,666,669,670,673],{},"Working as in PostgreSQL: sequences and identity columns, generated stored columns, views\nand materialized views, PL\u002FpgSQL triggers, deferrable foreign keys, ",[29,643,644],{},"ON DELETE CASCADE",",\ndeclarative partitioning, partial and expression indexes, ",[29,647,648],{},"COLLATE",[29,650,651],{},"ON CONFLICT",",\n",[29,654,655],{},"FOR UPDATE SKIP LOCKED",", savepoints, advisory locks, and the ",[29,658,659],{},"uuid-ossp",[29,661,662],{},"pgcrypto",[29,664,665],{},"hstore",[29,667,668],{},"citext"," and ",[29,671,672],{},"pg_trgm"," extensions.",[56,675,677],{"id":676},"table-and-database-sizes","Table and database sizes",[14,679,680,681,684,685,688,689,692,693,696],{},"YugabyteDB answers ",[29,682,683],{},"pg_relation_size"," with ",[29,686,687],{},"0"," for every table and ",[29,690,691],{},"pg_database_size"," with\n",[29,694,695],{},"NULL",", because rows live in DocDB tablets rather than in relation files. Data Explorer\nreads the total relation size instead when it is talking to YugabyteDB, so sizes appear as\nthey do for any other connection. An empty table still shows no size, on both engines.",[14,698,699,700,703,704,707],{},"Row counts come from the usual statistics and are accurate; a table that has never been\nanalyzed reports ",[29,701,702],{},"-1"," in ",[29,705,706],{},"reltuples",", and Data Explorer falls back to an exact count for it.",[56,709,711],{"id":710},"diagnosing-a-slot-from-sql-does-not-work-here","Diagnosing a slot from SQL does not work here",[14,713,714,669,717,720],{},[29,715,716],{},"pg_logical_slot_peek_changes",[29,718,719],{},"pg_logical_slot_peek_binary_changes"," always fail on\nYugabyteDB:",[303,722,725],{"className":723,"code":724,"language":163,"meta":308},[345],"ERROR: requested WAL segment pg_wal\u002F000000010000000000000000 has already been removed\n",[29,726,724],{"__ignoreMap":308},[14,728,729],{},"There is no WAL file behind a YugabyteDB slot for those functions to read. The slot itself\nis fine - only this way of inspecting it is unavailable. Use a real replication client to\ncheck whether a slot streams.",[731,732,733],"style",{},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}",{"title":308,"searchDepth":399,"depth":399,"links":735},[736,740,745,746,747],{"id":58,"depth":399,"text":59,"children":737},[738],{"id":120,"depth":739,"text":121},3,{"id":275,"depth":399,"text":276,"children":741},[742,743,744],{"id":290,"depth":739,"text":291},{"id":329,"depth":739,"text":330},{"id":433,"depth":739,"text":434},{"id":506,"depth":399,"text":507},{"id":676,"depth":399,"text":677},{"id":710,"depth":399,"text":711},"Connect DBConvert Streams to YugabyteDB YSQL - Load and CDC in both directions, the two prerequisites for using YugabyteDB as a CDC source, and the PostgreSQL features YSQL does not have.","md",{},false,"\u002Fdocs\u002Fconnections\u002Fyugabytedb",null,{"title":5,"description":748},"docs\u002Fconnections\u002Fyugabytedb","OIoBcGJqCyvO4qiKWtbnFmYjdQWZ39DJP9BZ27AEJ5w",1789058293783]